从delphi XE调用c++ DLL时出现异常

Exception when calling a C++ DLL from Dephi XE

本文关键字:异常 DLL c++ delphi XE 调用      更新时间:2023-10-16

我试图调用一个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("%sn", 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指针数据类型,所以我不认为这是问题所在。

这是我第一次尝试调用返回字符串的函数,所以我怀疑我不理解通过引用字符串数组调用的一些东西。

有什么建议,我应该如何调用这个函数不同,以避免什么似乎是垃圾内存?

你这里有几个问题。

首先,Delphi中的函数声明是错误的。首先,它同时声明为cdeclstdcall。它必须是其中之一;两者不能同时发生。

另外,在fptr变量上有一个额外的解引用级别。

声明表明它是一个指针:

filep *fptr

你在Delphi声明中说过它是一个指针:

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作为调用约定):

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;
相关文章: