使用字符串从 delphi 调用 c dll
call c dll from delphi with strings
我正在尝试从 Delphi XE5 调用一个 dll。
我花了一天左右的时间在谷歌上搜索 "Call C DLL from Delphi" 之类的东西,找到了很多页面,但没有任何帮助。
我收到了如何调用 VB 中的 dll 的示例:
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 在第一个参数中接受命令,returns 在第二个参数中获取结果文本。
这是我生成的 Delphi 代码,用于尝试调用 DLL。我知道 dll 加载是因为它有一个显示的初始屏幕。当我调用 dll 时没有生成错误。你会看到我使用数组分配 space 然后将它们的位置分配给 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;
您正在使用 Delphi 的 Unicode 版本,其中 Char
是 16 位 WideChar
的别名,PChar
是 [=15] 的别名=].
只需将 Char
替换为 AnsiChar
,将 PChar
替换为 PAnsiChar
。
function IxCommand(command, mailbox: PAnsiChar): Cardinal;
stdcall; external 'IxxDLL.dll';
return 值是 UINT
,映射到 Delphi 中的 Cardinal
。
您使用的调用代码过于复杂。我会这样做:
var
retval: Cardinal;
mailbox: array [0..134] of AnsiChar;
....
retval := IxCommand('Accel?:a', mailbox);
// check retval for errors
如您所见,存在缓冲区溢出的范围。我不确定你打算如何防止这种情况。该库的文档(如果存在)可能会解释如何操作。
问题出在字符编码上。在Delphi 2009+中,PChar
是PWideChar
的别名,但是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;
我正在尝试从 Delphi XE5 调用一个 dll。
我花了一天左右的时间在谷歌上搜索 "Call C DLL from Delphi" 之类的东西,找到了很多页面,但没有任何帮助。
我收到了如何调用 VB 中的 dll 的示例:
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 在第一个参数中接受命令,returns 在第二个参数中获取结果文本。
这是我生成的 Delphi 代码,用于尝试调用 DLL。我知道 dll 加载是因为它有一个显示的初始屏幕。当我调用 dll 时没有生成错误。你会看到我使用数组分配 space 然后将它们的位置分配给 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;
您正在使用 Delphi 的 Unicode 版本,其中 Char
是 16 位 WideChar
的别名,PChar
是 [=15] 的别名=].
只需将 Char
替换为 AnsiChar
,将 PChar
替换为 PAnsiChar
。
function IxCommand(command, mailbox: PAnsiChar): Cardinal;
stdcall; external 'IxxDLL.dll';
return 值是 UINT
,映射到 Delphi 中的 Cardinal
。
您使用的调用代码过于复杂。我会这样做:
var
retval: Cardinal;
mailbox: array [0..134] of AnsiChar;
....
retval := IxCommand('Accel?:a', mailbox);
// check retval for errors
如您所见,存在缓冲区溢出的范围。我不确定你打算如何防止这种情况。该库的文档(如果存在)可能会解释如何操作。
问题出在字符编码上。在Delphi 2009+中,PChar
是PWideChar
的别名,但是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;