2009-09-09 121 views
7

我试图用一个C++ DLL从一个本地程序。我下面的虚方法的情况作为解释here德尔福PChar类型C++为const char *

比方说我的C++函数签名的形式

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

和相应的德尔福签名

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

而且某处从德尔福计划我可以致电

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

c ontrol进入dll,但szIp和szPort形式参数只接收从delphi程序传过来的ip和端口的第一个字符。

据我所知,它与空在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. 

这也不奏效。当我WritelnpzIppzPort我得到奇怪的结果。

忘了告诉,从C++ DLL的所有成员函数编译__stdcall并远销正确

回答

17

2010年的Delphi(和Delphi 2009)的 “char” 类型实际上是一个WIDEChar - 即,16个位宽。所以当你调用你的C++函数时,如果期望CHAR的宽度是8位(所谓的“ANSI”而不是UNICODE),那么它会误解输入参数。

例如如果你通过字符串'ABC'#0(我显式地显示了null终止符,但这只是Delphi中一个字符串的隐式部分,并且不需要特别添加),它将一个指针传递给一个8字节序列,不是 4个字节!

但是,因为在你的字符串中的3个字符只有8位代码点值(以Unicode而言,这意味着什么C++代码“看见”则是一个字符串,如:

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

这可以解释为什么你的C++代码,似乎只待获取字符串的第一个字符 - 这是看到的#0在第一个字符的2个字节,并假定它是整个字符串空终止。

你要么需要修改你的C++代码,以正确接收指向WideChar字符串或在德尔福修改函数签名和您的字符串之前转换为德尔福代码ANSIString长传递那些对C++函数:

修订函数签名:

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

和相应的“长手”表示的字符串转换为甲调用函数之前NSIString - 编译器可以照顾这对你,但你可能会发现它的帮助,使之在你的代码清晰,而不是依靠“神奇编译”:

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

    pObj.Setup(sIPAddress, sPort); 

    // etc... 
+0

感谢您的更详细的解释:我的回答是一个很快的想法,证明是正确的,但我建议这是答案被接受。 – IanH 2009-09-09 12:01:26

+0

感谢@Deltics,工作。虽然需要进行一些小改动,但是需要进行编译以使delphi程序编译为 pObj.Setup(PAnsiChar(sIPAddress),PAnsiChar(sPort)); 特别感谢@IanH – rptony 2009-09-09 12:57:46

3

如果我理解正确的函数原型应该是STDCALL为好。

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

ps。 Delphi字符串已经以null结尾。

+0

嗯,它没有工作。结果相同。但是,当C++函数返回时,我可以摆脱访问冲突崩溃。所以,我想我正在取得进展:) – rptony 2009-09-09 11:14:02

+0

时间下降到组装视图:) – 2009-09-09 11:36:58

+0

使stdcall我也解决了其他几个问题,提示+1 – rptony 2009-09-09 13:20:03

4

在两种编译器烧焦大小相同?如果您使用的是D2009/D2010,char现在是16位。

+0

是啊我使用D2010。我的C++代码是32位。所以字符大小应该匹配正确? – rptony 2009-09-09 11:16:28

+2

不一定:BCB4是一个32位C++编译器,但char是一个字节。你可以用第一个字符的0高位字节过早地终止你的字符串。 尝试更改上面的测试代码,以将szIP和szPort声明为AnsiString而不是字符串。 – IanH 2009-09-09 11:26:14

+0

投票赞成领导回答 – rptony 2009-09-09 13:19:10