从Delphi XE调用C ++ DLL时出现异常

时间:2014-03-09 22:42:36

标签: c++ delphi dll

我正在尝试调用这样定义的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指针数据类型,所以我不认为这是问题所在。

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

有关如何以不同方式调用此函数的任何建议,以避免看起来像是内存的垃圾?

1 个答案:

答案 0 :(得分:0)

你有几个问题。

首先,Delphi中的函数声明是错误的。首先,它同时声明为cdeclstdcall。它需要是一个或另一个;它不能同时发生。

此外,您在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}}