2009-09-09 29 views
7

Sto provando a utilizzare una DLL C++ da un programma nativo. Seguo lo scenario metodo virtuale come spiegato hereDelphi Da PChar a C++ const char *

consente di dire la mia C firma funzione ++ è della forma

int Setup(const char* szIp, const char* szPort); 

e la corrispondente firma Delphi è

function Setup(ip, port: PChar):Integer: virtual; cdecl; abstract; 

E da qualche parte dal programma Delphi posso chiamare

pObj.Setup('192.168.1.100', '97777'); 

Il c ontrol entra nella DLL, ma i parametri formali szIp e szPort ricevono solo il primo carattere dell'ip e della porta che ho passato dal programma delphi.

Capisco che ha a che fare con terminazione null la stringa correttamente in Delphi. Quindi avevo provato anche questo.

var 
    pzIp, pzPort: PChar; 
    szIp, szPort: string; 

begin 
    szIp := '192.168.1.2'; 
    szPort := '9777'; 
    //initilize memory for pchar vars 
    GetMem(pzIp, Length(szIp)+1); 
    GetMem(pzPort, Length(szPort)+1); 
    //null terminate the strings 
    pzIp[Length(szIp)+1] := #0; 
    pzPort[Length(szPort)+1] := #0; 
    //copy strings to pchar 
    StrPCopy(pzIp, szIp); 
    StrPCopy(pzPort, szPort); 
end. 

Anche questo non funziona. Quando ho WritelnpzIp e pzPort ottengo risultati strani.

dimenticato di dire, tutte le funzioni di membro dalla DLL C++ sono compilate con __stdcall ed esportati correttamente

risposta

17

In Delphi 2010 (e Delphi 2009) del tipo "char" è in realtà un widechar - cioè, larga 16 bit. Quindi, quando chiamate la vostra funzione C++, se questo si aspetta che CHAR abbia una larghezza di 8 bit (il cosiddetto "ANSI", piuttosto che UNICODE), allora interpreterà male il parametro di input.

ad es. se si passa la stringa 'ABC' # 0 (sto mostrando il terminatore null in modo esplicito, ma questo è solo una parte implicita di una stringa in Delphi e non ha bisogno di essere aggiunti in particolare) questo passa un puntatore ad un 8 byte sequenza, NON 4 byte!

Ma perché i 3 caratteri nella stringa sono solo valori di codice-punto 8-bit (in termini Unicode, questo significa che ciò che il codice C++ "vede" è una stringa che assomiglia:

'A'#0'B'#0'C'#0#0#0 

Il che spiegherebbe perché il tuo codice C++ sembra solo ottenere il primo carattere della stringa: sta vedendo lo # 0 nel 2o byte di quel primo carattere e supponendo che sia il terminatore nullo per l'intera stringa.

vi sia bisogno di modificare il codice C++ per ricevere correttamente i puntatori ai WideChar stringhe, o modificare la firma della funzione in Delphi e convertire le stringhe di ANSIString nel codice Delphi prima passare quelli per la funzione C++ :

firma funzione di revisione:

function Setup(ip, port: PANSIChar):Integer: virtual; stdcall; abstract; 

e il corrispondente "lunga mano" che mostra la conversione di stringhe di a NSIString prima di chiamare la funzione - il compilatore può prendersi cura di questo per voi, ma si potrebbe trovare utile per chiarire nel codice, piuttosto che basarsi su "compilatore magica":

var 
    sIPAddress: ANSIString; 
    sPort: ANSIString; 
    begin 
    sIPAddress := '192.168.1.100'; 
    sPort  := '97777'; 

    pObj.Setup(sIPAddress, sPort); 

    // etc... 
+0

Grazie per la spiegazione più dettagliata: la mia risposta è stata una rapida idea che si è dimostrata giusta, ma la raccomando come risposta da accettare. – IanH

+0

Grazie a @Deltics, ha funzionato. Tuttavia, è stato necessario effettuare un piccolo cambiamento per compilare il programma delphi pObj.Setup (PAnsiChar (sIPAddress), PAnsiChar (sPort)); Un ringraziamento speciale anche a @IanH – rptony

3

Se ho capito bene il tuo prototipo di funzione dovrebbe essere stdcall pure.

function Setup(ip, port: PChar):Integer: virtual; stdcall; abstract; 

ps. Le stringhe Delphi sono già terminate da null.

+0

hmm, non ha lavorato. Lo stesso risultato. Ma potrei sbarazzarmi di un crash di violazione di accesso quando la funzione C++ tornava. Quindi, suppongo che sto facendo progressi :) – rptony

+0

tempo di passare alla vista dell'assieme :) –

+0

facendo sì che stdcall mi abbia risolto qualche altro problema, +1 per il suggerimento – rptony

4

Il char ha le stesse dimensioni in entrambi i compilatori? Se si utilizza D2009/D2010, il char è ora a 16 bit.

+0

sì, sto usando D2010. E il mio codice C++ è a 32 bit. Quindi la dimensione del carattere dovrebbe corrispondere a destra? – rptony

+2

Non necessariamente: BCB4 è un compilatore C++ a 32 bit, ma un char è un byte. È possibile terminare in modo anomalo la stringa prematuramente con il byte alto 0 per il primo carattere. Provare a cambiare il codice di test qui sopra per dichiarare szIP e szPort come AnsiString invece di stringa. – IanH

+0

su per la risposta per la risposta – rptony

Problemi correlati