2009-09-09 18 views
7

Estoy tratando de usar un dll C++ desde un programa nativo. Estoy siguiendo el escenario método virtual como se explica hereDelphi PChar a C++ const char *

permite decir mi C++ firma de la función es de la forma

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

y la firma Delphi correspondiente es

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

Y en alguna parte del programa de Delphi Puedo llamar al

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

La c ontrol entra en el dll, pero los parámetros formales szIp y szPort solo reciben el primer carácter de la ip y el puerto que he pasado del programa delphi.

Entiendo que tiene que ver con nulo que termina la cadena correctamente en delphi. Así que también intenté lo siguiente.

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. 

Esto tampoco funciona. Cuando yo WritelnpzIp y pzPort obtengo resultados extraños.

olvidó decirle, todas las funciones miembro de la DLL de C++ son recopilados con __stdcall y se exportan correctamente

Respuesta

17

En Delphi 2010 (y Delphi 2009) el tipo "char" es en realidad un WIDEChar, es decir, 16 bits de ancho. Entonces, cuando llama a su función C++, si espera que CHAR tenga 8 bits de ancho (llamada "ANSI", en lugar de UNICODE), entonces malinterpretará el parámetro de entrada.

p. Ej. si pasa la cadena 'ABC' # 0 (estoy mostrando el terminador nulo explícitamente pero esto es solo una parte implícita de una cadena en Delphi y no necesita ser agregado específicamente) esto pasa un puntero a un 8 byte secuencia, NO 4 bytes!

Pero debido a los 3 caracteres en la cadena tienen sólo los valores de código de punto de 8 bits (en términos Unicode, esto significa que lo que el código C++ "ve" es una cadena que parece:

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

Lo que explicaría por qué su código C++ parece estar obteniendo el primer carácter de la cadena: está viendo # 0 en el 2nd byte del primer carácter y suponiendo que es el terminador nulo de toda la cadena.

O se necesita modificar su código C++ para recibir correctamente los punteros a WideChar cuerdas, o modificar la firma de función en Delphi y convertir sus cadenas a ANSIString en el código Delphi antes pasar los a la función de C++ :

función revisado firma:

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

y la correspondiente "mano larga", mostrando la conversión de cadenas a un NSIString antes de llamar a la función - el compilador puede hacerse cargo de esto para usted, pero es posible que le resulte útil para que quede claro en el código en lugar de confiar en la "magia compilador":

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

    pObj.Setup(sIPAddress, sPort); 

    // etc... 
+0

Gracias por la explicación más detallada: mi respuesta fue rápida, lo que resultó ser cierto, pero lo recomiendo como la respuesta para ser aceptado. – IanH

+0

Gracias @Deltics, eso funcionó. Sin embargo, era necesario realizar un pequeño cambio para que el programa delphi compilara pObj.Setup (PAnsiChar (sIPAddress), PAnsiChar (sPort)); Agradecimiento especial a @IanH también – rptony

3

Si he entendido bien el prototipo de la función debe ser stdcall también.

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

ps. Las cadenas de Delphi ya tienen terminación nula.

+0

hmm, no lo hizo trabajó. El mismo resultado. Pero podría deshacerme de un bloqueo de violación de acceso cuando se devuelva la función C++. Entonces, supongo que estoy progresando :) – rptony

+0

hora de soltar a la vista de ensamblaje :) –

+0

haciéndolo stdcall también me ha resuelto algunos otros problemas, +1 para la sugerencia – rptony

4

¿Tiene el mismo tamaño en ambos compiladores? Si está utilizando D2009/D2010, char ahora tiene 16 bits.

+0

sí, estoy usando D2010. Y mi código C++ es de 32 bits. Entonces, ¿el tamaño del personaje debe coincidir con el correcto? – rptony

+2

No necesariamente: BCB4 es un compilador C++ de 32 bits, pero un char es un byte. Puede terminar la cadena prematuramente con el byte alto 0 para el primer carácter. Intente cambiar el código de prueba anterior para declarar szIP y szPort como AnsiString en lugar de cadena. – IanH

+0

arriba voto para dar lugar a la respuesta – rptony