使用Delphi调用C动态链接库

4

我有一个具有以下签名的Dll函数:

UInt32 Authenticate(uint8 *Key);

我正在使用Delphi进行此操作:
function Authenticate(Key:string) : UInt32; external 'mylib.dll' name 'Authenticate';

但是总是返回函数错误代码10,导致应用程序崩溃:\

有没有正确的处理方法?

更新: 谢谢大家!你们最棒了!


当然,uint8并不等同于字符串...你需要传递什么作为函数的键,只是一个字节指针吗? - jachguate
@jachguate 在这种情况下,uint8* 等同于 PAnsiChar - David Heffernan
@David,这种情况下“equivalent”是含糊不清的XD。在我看来,uint8只相当于PByte。期望通过uint8指针传递PAnsiChar的函数并不是等价的问题,而是C端偏好的问题。我并不完全同意这一点。 - jachguate
3个回答

7
你的代码存在一些问题。
1)在Delphi中,uint8相当于Byte,而不是String
2)C代码使用的是编译器的默认调用约定,通常为__cdecl。而Delphi的默认调用约定则是register。它们彼此不兼容。如果调用约定不匹配,在运行时函数调用期间,堆栈和CPU寄存器将无法正确管理。
C代码的直译应该是这样的:
function Authenticate(Key: PByte) : UInt32; cdecl; external 'mylib.dll';

不过,如果假设该函数确实需要一个以null结尾的字符串,则请改为执行以下操作:

// the function is expecting a pointer to 8-bit data,
// so DO NOT use `PChar`, which is 16-bit in Delphi 2009+...
function Authenticate(Key: PAnsiChar) : UInt32; cdecl; external 'mylib.dll';

我建议使用第一种声明方式,因为它与原始的C代码匹配。即使函数需要以空字符结尾的字符串作为输入,你仍然可以通过类型转换使用PByte传递它:

var
  S: AnsiString;
begin
  Authenticate(PByte(PAnsiChar(S)));
end;

或者,如果该函数允许将空字符串作为NULL输入:

var
  S: AnsiString;
begin
  Authenticate(PByte(Pointer(S)));
end;

绝对是一个不错的开始。值得注意的是,Delphi在低于Delphi 2008版本中使用8位ASCII,此时应优先选择PChar。以下是有关Delphi字符串处理和与Windows兼容性的优秀链接:http://delphi.about.com/od/beginners/l/aa071800a.htm。 - paulsm4
5
即使在 Delphi 2009 之前的版本中,PAnsiChar 仍然比 PChar 更受欢迎。它使代码更加明确,表明它期望 8 位字符数据,并且如果项目以后升级到 Delphi 2009+ 版本,你不必记得将其从 PChar 更改为 PAnsiChar(为了与 C 代码保持兼容性)。 - Remy Lebeau

2
我不会对伟大的Remy的答案做出任何补充,但我想给出一些工具的列表,这些工具可以帮助将C DLL头文件转换为Pascal(没有特定的顺序): 请注意,这些转换器只能转换60-80%的代码,因此需要进行手动工作。
我能提供的最大时间节省提示是:尝试查找Visual Basic头文件翻译(如果存在于您的DLL中),并使用Marco Cantu的VB转换器http://www.marcocantu.com/tools/vb2delphi.htm。这可能会给您几乎100%的自动转换(当然,如果您只转换DLL头文件)。还有一个商业VBTO转换器,但试用版足以将VB DLL头文件转换为Pascal。在这里下载它:http://www.vbto.net 从C--/C++进行转换的其他提示:

虽然略微偏题,但我认为这对某些人可能会有用...


0

首先,将“string”更改为“pchar”。

除此之外可能还有其他问题。


如果使用Delphi 2009+,请改用PAnsiChar - Remy Lebeau
PByteArray 更精确地表示变量类型。 - Jay
2
这不是一个答案。还有很多其他问题,而且PChar也是错误的,因为PChar并不能替代“指向8字节无符号整数”的指针(当然,string也不行)。最多应该作为对原问题的评论;它绝对不是一个答案。 - Ken White
1
@Ken - uint8是8位,而不是字节,即Byte。请参见http://msdn.microsoft.com/en-us/library/cc230388%28v=prot.10%29.aspx。 - Gerry Coll
@Gerry:当然是的。这是我的错别字,我没有仔细阅读自己写的内容。感谢您的纠正-不需要链接,但我很感激提供它的努力。再次感谢。 :-) - Ken White

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接