用* char调用dll,在Delphi中使用PAnsiChar或AnsiString?

问题描述

使用以下函数声明用C编写dll时:

WORD StartDownloadTo(char * pFileName);

对于Delphi 10.4,我应该将其转换为:

function StartDownloadTo(FileName: AnsiString): Word cdecl stdcall;

可以通过以下方式调用

var
  filename: string;
begin
  StartDownloadTo(AnsiString(FileName));
end;

function StartDownloadTo(FileName: PAnsiChar): Word cdecl stdcall;

可以通过以下方式调用

var
  filename: string;
begin
  StartDownloadTo(PAnsiChar(AnsiString(fileName)));
end;

两者似乎都有效。出于我不知道的原因,一个比另一个更好吗?

解决方法

您的任何声明都不正确。

正确的声明是:

function StartDownloadTo(FileName: PAnsiChar): Word; cdecl;

您在通话约定中发生了混淆。

虽然使用AnsiString似乎可行,但这实际上只是一个巧合。碰巧一个AnsiString变量指向字符串的第一个字符。为了在语义上正确,您应该使用PAnsiChar

此外,如果您的字符串为空,则需要将指针传递给以零结尾的字符,这就是将空字符串表示为C字符串的方式。但是,如果将参数声明为AnsiString,则空字符串将导致传递nil。如果您使用PAnsiChar,则调用代码中的PAnsiChar强制转换会导致对空字符串进行所需的处理。

但是请注意,使用8位文本将无法支持当前用户语言环境之外的任何字符。我希望看到C代码接受const wchar_t *pFileName,并且您的Delphi代码使用PWideChar