在Delphi中从C DLL获取字符串返回值

在Delphi中从C DLL获取字符串返回值,c,delphi,dll,C,Delphi,Dll,我有一个用C编写的遗留DLL,其中包含一个返回字符串的函数,我需要从Delphi访问该函数。关于DLL的唯一信息是访问函数的VB声明: 公共声明函数将Str Lib“strlib”(Str作为字符串)解密为字符串 我尝试了以下方法但没有成功: 声明: function DecryptStr(s: PChar): PChar; cdecl; external 'strlib.dll'; 用法: var p1, p2 : pchar; begin GetMem( p1, 255 );

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

公共声明函数将Str Lib“strlib”(Str作为字符串)解密为字符串

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

声明:

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崩溃,并导致访问冲突。我不知所措


有什么建议吗?

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


另外,确保检查字符串是ANSI(LPSTR/LPCSTR)还是UNICODE(LPWSTR/LPCWSTR)。我不知道VB或Delphi,所以我不知道它们在默认情况下使用的是什么。

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

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

如果无效,请在此处发布VB声明。

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

考虑如下重写测试代码:

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仍然失败,请仔细阅读。

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


通过这种方式,您将很容易看到如何更正此问题。

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

正如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分配的内存的指针,则需要注意如何释放该内存

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

为什么假设传入的字符串正好是255个字符长?您需要为p1中的字符分配长度(p1)+1字节,并在末尾分配一个#0字符

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


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

我在我的解决方案中加入了它,因为我已经对它进行了很多研究,但在任何答案中都没有找到它

C++函数看起来是这样的:

int  __stdcall DoSomething(char * _name);
var s: PAnsiChar;
begin
  GetMem(s, 255);
  DoSomething(s);
  // s now contains the value returned from the C DLL
end;
为了让它在Delphi中工作,我声明了以下函数

function DoSomething(name: PAnsiChar): integer; stdcall; external 'somedll.dll';
然后当我调用时,我有一个函数如下所示:

int  __stdcall DoSomething(char * _name);
var s: PAnsiChar;
begin
  GetMem(s, 255);
  DoSomething(s);
  // s now contains the value returned from the C DLL
end;
我试着用PChar代替PAnsiChar,但我得到的回报是垃圾。另外,如果我在Delphi中声明函数,并将参数设置为var,那么当我尝试读取它时会出现异常


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

他已经发布了VB声明,比Delphi声明高出了两段。对不起,你说得对,CesarB,我没有注意到,因为他没有将其标记为代码。行“strppy(p2)”正确吗?应该是“strppy(p1)”吗?