我正在尝试使用本机程序中的C ++ DLL。我正在按照here
所述的虚拟方法场景进行操作让我说我的C ++函数签名的形式是
int Setup(const char* szIp, const char* szPort);
相应的delphi签名是
function Setup(ip, port: PChar):Integer: virtual; cdecl; abstract;
从delphi程序的某个地方我可以调用
pObj.Setup('192.168.1.100', '97777');
控件进入dll,但是szIp和szPort形式参数只接收我从delphi程序传递的ip和port的第一个字符。
我知道它与null在delphi中正确终止字符串有关。所以我也试过了以下内容。
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.
这也是一种工作方式。当我Writeln
pzIp
和pzPort
时,我得到了奇怪的结果。
忘了说,来自C ++ dll的所有成员函数都使用__stdcall
进行编译并正确导出
答案 0 :(得分:17)
在Delphi 2010(和Delphi 2009)中,“char”类型实际上是WIDEChar - 即16位宽。因此,当您调用C ++函数时,如果期望CHAR为8位宽(所谓的“ANSI”,而不是UNICODE),那么它将错误解释输入参数。
e.g。如果你传递字符串'ABC'#0 (我显式地显示空终止符,但这只是Delphi中字符串的隐式部分,不需要特别添加)指向 8字节序列的指针, NOT 4字节!
但是因为字符串中的3个字符只有8位代码点值(在Unicode术语中,这意味着C ++代码“看到”的字符串看起来像:
'A'#0'B'#0'C'#0#0#0
这可以解释为什么你的C ++代码似乎只是获得字符串的第一个字符 - 它在第一个字符的第二个字节中看到#0 并假设它是整个字符串的空终止符。
您需要修改C ++代码以正确接收指向 WideChar 字符串的指针,或修改Delphi中的函数签名并将字符串转换为Delphi代码中的 ANSIString 之前将它们传递给C ++函数:
修改功能签名:
function Setup(ip, port: PANSIChar):Integer: virtual; stdcall; abstract;
和相应的“Long hand”显示在调用函数之前将字符串转换为 ANSIString - 编译器可能会为您解决此问题,但您可能会发现在代码中明确这一点很有帮助而不是依赖“编译魔术”:
var
sIPAddress: ANSIString;
sPort: ANSIString;
begin
sIPAddress := '192.168.1.100';
sPort := '97777';
pObj.Setup(sIPAddress, sPort);
// etc...
答案 1 :(得分:4)
两个编译器中的char大小相同吗?如果您使用的是D2009 / D2010,则char现在为16位。
答案 2 :(得分:3)
如果我理解正确,你的函数原型也应该是stdcall。
function Setup(ip, port: PChar):Integer: virtual; stdcall; abstract;
PS。 Delphi字符串已经以空值终止。