2009-09-09 125 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