2015-10-27 122 views
3

我想從Delphi XE5調用dll。從delphi調用c dll字符串

我花了一天左右的時間搜索諸如「從Delphi調用C DLL」之類的東西,並找到了一些頁面,但沒有什麼幫助。

我收到了如何調用該DLL在VB中的例子:


Declare Function IxCommand Lib "IxxDLL.dll" (ByVal command As String, ByVal mailbox As String) As Integer 

... 

Sub Command1_Click() 
     Dim command As String * 135 
     Dim mailbox As String * 135 

     command = "move:a,1000" 
     IxCommand(command, mailbox) 
End Sub 

還呼籲在VC++ 6.0的DLL:


#include "stdafx.h" 

#include "windows.h" 
#include "stdio.h" 
#include "string.h" 

typedef UINT (CALLBACK* LPFNIXDLLFUNC)(char *ixstr, char *mbstr); 

int main(int argc, char* argv[]) 
{ 
    HINSTANCE hDLL;    // Handle to DLL 
    LPFNIXDLLFUNC lpfnIxDllFunc; // Function pointer 

    hDLL = LoadLibrary("IxxDLL.dll"); 

    if (hDLL == NULL) // Fails to load Indexer LPT 
    { 
     printf("Can't open IxxDLL.dll\n"); 
     exit(1); 
    } 
    else // Success opening DLL - get DLL function pointer 
    { 
     lpfnIxDllFunc = (LPFNIXDLLFUNC)GetProcAddress(hDLL, "IxCommand"); 
    } 

    printf("Type Indexer LPT command and press <Enter> to send\n"); 
    printf("Type \"exit\" and press <Enter> to quit\n\n"); 

    while(1) 
    { 
     char ix_str[135];  // String to be sent to Indexer LPT 
     char mailbox_str[135]; // Results from call into Indexer LPT 

     gets(ix_str); // Get the string from the console 
     if(_stricmp(ix_str, "exit") == 0) // Leave this program if "exit" 
      break; 
     lpfnIxDllFunc(ix_str, mailbox_str); // Otherwise call into Indexer LPT 
     printf("%s\n\n", mailbox_str);  // Print the results 
    } 

    FreeLibrary(hDLL); 
    return 0; 
} 

我注意到併發症是需要在調用DLL之前定義內存分配的大小,如上所示。

dll在第一個參數中接受一個命令,並在第二個參數中返回結果文本。

這是我生成的用於嘗試和調用DLL的Delphi代碼。我知道DLL加載,因爲它有一個啓動畫面顯示。我調用dll時不會生成錯誤。你會看到我使用數組來分配空間,然後將它們的位置分配給Pchar變量。我沒有任何原始DLL的頭文件,也沒有源代碼。你會看到我使用stdcall聲明瞭外部函數,但我也嘗試過沒有改變的cdecl。

問題:在arg2中返回的信息不是預期的文本字符串,而是一個翻譯爲非英文字符(看起來像中文)的字符串。

我猜我沒有發送正確的變量類型的DLL。

問題:任何人都可以幫助我制定外部函數的聲明並正確使用它,以便根據需要取回文本字符串?

見下文:


function IxCommand (command : PChar; mailbox : PChar) : Integer; stdcall; external 'IxxDLL.dll'; 

... 

procedure TfrmXYZ.btn1Click(Sender: TObject); 

var 
    LocalResult : Integer; 
    arg1, 
    arg2  : PChar; 


    ArrayStrCmd : array[0..134] of char; 
    ArrayStrMbx : array[0..134] of char; 

begin 

    ArrayStrCmd := 'Accel?:a' + #0; 
    ArrayStrMbx := '   ' + #0; 
    arg1 := @ArrayStrCmd; 
    arg2 := @ArrayStrMbx; 


    LocalResult := IxCommand(arg1, arg2); 

end; 

回答

4

問題是字符編碼。在Delphi 2009+中,PCharPWideChar的別名,但該DLL使用的是Ansi字符串,因此您需要使用PAnsiChar而不是PChar

試試這個:

function IxCommand (command : PAnsiChar; mailbox : PAnsiChar) : Integer; stdcall; external 'IxxDLL.dll'; 

... 

procedure TfrmXYZ.btn1Click(Sender: TObject); 
var 
    LocalResult : Integer; 
    ArrayStrCmd : array[0..134] of AnsiChar; 
    ArrayStrMbx : array[0..134] of AnsiChar; 
begin 
    ArrayStrCmd := 'Accel?:a' + #0; 
    LocalResult := IxCommand(ArrayStrCmd, ArrayStrMbx); 
end; 

或者:多的快速和有用的答案

function IxCommand (command : PAnsiChar; mailbox : PAnsiChar) : Integer; stdcall; external 'IxxDLL.dll'; 

... 

procedure TfrmXYZ.btn1Click(Sender: TObject); 
var 
    LocalResult : Integer; 
    ArrayStrCmd, 
    ArrayStrMbx : AnsiString; 
begin 
    SetLength(ArrayStrCmd, 135); 
    StrPCopy(ArrayStrCmd, 'Accel?:a'); 
    SetLength(ArrayStrMbx, 135); 
    LocalResult := IxCommand(PAnsiChar(arg1), PAnsiChar(arg2)); 
end; 
+0

AnsiString版本分配比具有固定長度數組的版本更小的緩衝區。你應該在這裏使用'SetLength'。並且不需要填充輸出緩衝區。 –

+0

這真的取決於DLL函數的性質以及它的參數實際表示的內容。但無論如何,我已經更新了我的例子。 –

+0

C代碼示例就是我們應該將其作爲模板的工具,而不是提問者的嘗試翻譯。它分配長度爲135的數組,並且不初始化郵箱的內容。 –

2

您正在使用德爾福的Unicode版本針對Char是一個別名爲16位WideChar,並PChar是一個別名PWideChar

簡單地用AnsiCharPCharPAnsiChar代替Char

function IxCommand(command, mailbox: PAnsiChar): Cardinal; 
    stdcall; external 'IxxDLL.dll'; 

返回值是UINT映射到Cardinal在Delphi。

您使用的調用代碼是不必要的複雜。我會這樣做:

var 
    retval: Cardinal; 
    mailbox: array [0..134] of AnsiChar; 
.... 
retval := IxCommand('Accel?:a', mailbox); 
// check retval for errors 

如您所見,緩衝區溢出的範圍。我不確定你是如何防範的。圖書館的文件如果存在的話,可能會解釋如何。

+0

感謝。它現在按預期工作。歡呼! –