我正在尝试调用这样定义的C ++ DLL函数:
int read_record (filep *fptr, int key, char *contents, int *status)
这是一个广泛使用的DLL,所以我很确定我遇到的问题是我如何调用该函数。
DLL文档有这个如何调用它的例子
TFILETYPE *fptr; /* file pointer
char contents[80];
int status = 0;
int single = key;
if (read_record(fptr, key, card, &status)) break;
printf("%s\n", card);
以下是我认为应该起作用的内容,而且几乎可以:
type
TCharArray = Array[1..100] of AnsiChar; // Function returns an array less than 100 char
var
read_record : function( var fptr: TFILETYPE;
Key: Integer;
var Contents: TCharArray; // function fills this in
var Status: Integer): Integer cdecl stdcall;
Procedure Test;
var
Contents: TCharArray;
Status: Integer;
Key: Integer;
begin
@read_record:= GetProcAddress(DLLHandle, 'read_record');
for Key := 1 to 10 do
begin
Contents[1] := #0; // shouldn't be necessary
if (read_record( fptr^, Key, Contents, Status) <> 0) OR (Status <> 0) then
ShowMessage('Error')
else
ShowMessage(Contents); // This shows the expected proper string on all 10 calls
...Other calls at this point to other functions in the DLL result in
an Exception writing to x01a.
end;
Delphi XE的多次调用工作正常。但在那之后,当我在过去一直工作的DLL中调用不同的函数时,我得到一个异常写入x0000001a,我怀疑这意味着我已经破坏了内存或堆栈。
我在调用dll中的其他函数时使用的* fptr指针数据类型,所以我不认为这是问题所在。
这是我第一次尝试调用一个返回字符串的函数,所以我怀疑我不会通过引用字符串数组来理解它。
有关如何以不同方式调用此函数的任何建议,以避免看起来像是内存的垃圾?
答案 0 :(得分:0)
你有几个问题。
首先,Delphi中的函数声明是错误的。首先,它同时声明为cdecl
和stdcall
。它需要是一个或另一个;它不能同时发生。
此外,您在fptr
变量上有额外的解除引用级别。
声明表明它是一个指针:
filep *fptr
你在德尔福声明中已经说过它是一个指针:
var fptr: TFileType
但是你传给一个指针指针:
fptr^
将您对DLL函数的调用更改为
if (read_record( fptr, Key, Contents, Status) <> 0) OR (Status <> 0)
(我认为您对结果的测试实际上应该是<> 0) AND (Status <> 0)
,但没有我不确定的文档。)
如果您确实需要在将Contents
传递给DLL之前初始化FillChar(Contents, SizeOf(Contents), #0)
,则应使用ZeroMemory
(或stdcall
)来执行此操作,BTW。
作为补充建议,您可以稍微简化一下代码(我已选择var
read_record : function( var fptr: TFILETYPE;
Key: Integer;
Contents: PAnsiChar; // function fills this in
var Status: Integer): Integer stdcall;
var
Contents: AnsiString;
...
begin
SetLength(Contents, 100);
if (read_record(fptr, Key, PAnsiChar(Contents), Status)...
....
end;
作为调用约定):
{{1}}