4

我有一个用 C 编写的遗留 DLL,其中包含一个返回字符串的函数,我需要从 Delphi 访问这个函数。我拥有的关于 DLL 的唯一信息是用于访问函数的 VB 声明:

公共声明函数 DecryptStr Lib "strlib" (Str As String) As String

我尝试了以下但没有成功:

宣言:

function DecryptStr(s: PChar): PChar; cdecl; external 'strlib.dll';

用法:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 );
  StrPCopy( p2, 'some string to decrypt' );
  p1 := DecryptStr( p2 );
end;

这始终使 DLL 因访问冲突而崩溃。我不知所措。

有什么建议么 ?

4

9 回答 9

5

考虑重写您的测试代码,如下所示:

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 ); // initialize
  GetMem( p2, 255 );
  StrPLCopy( p2, 'some string to decrypt', 255 ); // prevent buffer overrun
  StrPLCopy( p1, DecryptStr( p2 ), 255); // make a copy since dll will free its internal buffer
end;

如果调用 DecryptStr 仍然失败,请仔细阅读http://support.microsoft.com/kb/187912

于 2008-10-26T07:26:42.497 回答
4

p2 未初始化。StrPCopy 将字符串复制到随机内存位置。最有可能的调用约定是stdcall。

于 2008-10-26T06:24:13.887 回答
2

我在这里猜,但你确定它是 cdecl 吗?如果 VB 声明没有提到它,我会假设它实际上是一个 STDCALL 函数(STDCALL 在 Windows 上很常见,因为几乎所有的原生 API 都使用它)。调用一个调用约定的函数,就好像它是另一个调用约定的函数一样,真的会弄乱堆栈,通常会导致崩溃。

此外,请务必检查字符串是 ANSI (LPSTR/LPCSTR) 还是 UNICODE (LPWSTR/LPCWSTR)。我不知道VB或Delphi,所以我不知道每个人默认使用什么。

于 2008-10-26T00:15:01.013 回答
1

正如 Jozz 所说,在您的示例中从未初始化 p2 (您将字符串复制到的位置)。

试试这个。

var
  p1, p2 : pchar;
begin
  GetMem( p2, 255 ); // allocate memory for 'some string...'
  StrPCopy( p2, 'some string to decrypt' );
  p1 := DecryptStr( p2 );
end;

此外,您通过调用 Getmem(p1,...) 分配的内存将被泄露,因为 p1 被 DecryptStr 的函数返回覆盖。

但是,我有点担心 DecryptStr 到底返回了什么,以及谁拥有 p1 指向的内存。如果它返回指向由 DLL 分配的内存的指针,则需要小心如何释放该内存。

于 2008-10-27T10:22:46.043 回答
0

我同意 CesarB,尝试使用 stdcall 指令将其声明为:

function DecryptStr(s: PChar): PChar; stdcall; external 'strlib.dll';

如果它不起作用,请在此处发布 VB 声明。

于 2008-10-26T00:39:54.193 回答
0

在这种情况下,最好的方法是调试您的程序并在执行回调之前和之后检查堆栈。怎么知道,它甚至可能是外部 DLL 中的错误?

这样你会很容易地看到如何纠正这个问题。

于 2008-10-26T17:20:55.700 回答
0

用 Borland C 或 C++Builder 编写的 dll 是否有意与 Delphi 一起使用?在这种情况下,它可以使用 pascal 指令进行编译。

于 2008-10-26T17:25:29.747 回答
0

字符串必须“初始化”的建议似乎是正确的。这是因为 C 将要求传入的字符串以空值结尾。检查文本末尾之后的缓冲区中的字符是否为空 (#0)。

为什么你认为传入的字符串正好是 255 个字符长?您需要为 p1 中的字符分配 Length(p1) + 1 个字节,最后分配一个 #0 字符。

此外,您的代码示例似乎对 p1 和 p2 的使用感到困惑。看起来 p1 是传递给您分配的 C DLL 的缓冲区,而 p2 是 DLL 分配的返回字符串。但随后代码将是(注意使用 p1 和 p2)

var
  p1, p2 : pchar;
begin
  GetMem( p1, 255 );
  StrPCopy( p1, 'some string to decrypt' );
  p2 := DecryptStr( p1 );
end;

更好的变量名称将帮助您更清楚地说明这一点。

于 2008-10-27T10:53:44.420 回答
0

我放弃了我的解决方案,因为我对此感到很困惑,并且在任何答案中都没有找到它。

C++ 函数如下所示:

int  __stdcall DoSomething(char * _name);

为了让它在 Delphi 中工作,我声明了以下函数

function DoSomething(name: PAnsiChar): integer; stdcall; external 'somedll.dll';

然后当我拨打电话时,我有一个如下所示的函数:

var s: PAnsiChar;
begin
  GetMem(s, 255);
  DoSomething(s);
  // s now contains the value returned from the C DLL
end;

我曾尝试使用 PChar 而不是 PAnsiChar 但我得到的只是垃圾。此外,如果我在 Delphi 中声明函数并将参数设置为var,当我尝试读取它时会出现异常。

希望这对任何人都有帮助..

于 2013-03-18T12:55:08.750 回答