1

我必须在 Delphi 6 中使用来自外部 C++ DLL 的编码函数。以下是提供的声明:

long <Function Name> (char *Data, long &Apply, char *ReturnVal, long &Size)

Data 是输入值,Apply 是布尔值(默认值:FALSE),ReturnVal 是来自 DLL 的返回值,Size 是 ReturnVal 的长度。

为了在 Delphi 6 中使用它,我编写了以下代码:

implementation
   const
     EncoderDLL = '<DLL NAME>';
     FunctionName = 'FUNCTION NAME';
   var
      _TEST : function(const Data : PChar; Apply : PInteger;stOutput : Pchar;
          iSize : PInteger) : integer; stdcall;
   .....
   .....
   var
     stInput,stOutput : string;
     iLength,i1,iResult : integer;
     hnd : THandle;
   begin
     iLength := 0;
     i1 := 0;
     stInput := Trim(edtInput.Text);
     hnd := SafeLoadLibrary(EncoderDLL);
     if hnd > 0 then
     begin
       @_TEST := GetProcAddress(hnd,FunctionName);
       if @_TEST <> nil then
       begin
         iResult := _TEST(PChar(stInput),@i1,PChar(StOutput),@iLength); // ERROR
       end;
     end;
     FreeLibrary(hnd);
  end;

我在注释为“错误”的行中遇到访问冲突

如果我将函数声明中的PChar替换为string,则访问冲突不会出现在同一行。它是在释放库时出现的。此外,iLength 参数的值已正确填充。

任何人都可以提供解决此问题的指示。

4

3 回答 3

3

我假设ReturnVal是一个输出参数(函数填充它)。您应该在代码中为该字符串保留内存。但是你应该保留多少内存呢?这些功能有一个共同的模式。您调用该函数两次

在您设置的第一个调用ReturnValnil,函数会在参数中填写它需要的大小Size

然后,您在StOutput缓冲区中保留那么多内存并再次调用该函数。这次你得到了结果。

iResult := _TEST(PChar(stInput),@i1,nil,@iLength); // First call
SetLength( stOutput, iLength ); // reserve memory
iResult := _TEST(PChar(stInput),@i1,PChar(stOutput),@iLength); // Second call

请注意,此函数可能遵循也可能不遵循此约定。但如果没有,就真的没有办法告诉你应该为输出参数保留多少内存。

另一件需要注意的是调用约定。C 和 C++ 函数默认为cdecl,并且您显示的声明没有另外说明。您已将其声明为stdcall在 Pascal 中。他们应该匹配。

于 2012-10-05T11:25:13.210 回答
3
  1. 您确定 stdcall 约定吗?如果 C++ 文本中没有明确的说明(如 WINAPI、__stdcall 等),则使用 cdecl。

  2. 不需要数据之前的'const'

  3. 为 StOutput 分配内存

于 2012-10-05T11:21:00.900 回答
2

保留 PChar,并在调用前将 StOutput 初始化为非空字符串(足够长)。

于 2012-10-05T11:13:23.327 回答