经过大量实验,我找到了一种方法,可以将 FreePascal 编译的 DLL 中的 PChar 与 Delphi 编译的 EXE 进行交换。我负责 DLL 和 EXE 源代码,但其中一个必须在 FreePascal 中,另一个在 Delphi 中。我的解决方案涉及DLL中的以下方法:
function GetAString(): PChar;
var aString: string;
begin
aString := 'My String';
result := StrAlloc(length(aString) + 1);
StrPCopy(result, aString);
end;
procedure FreeString(aString: PChar);
begin
StrDispose(aString);
end;
从 Delphi EXE 中,要调用 GetAString 方法,我需要调用 GetAString 方法,将 PChar 保存到实际的 Delphi String 并调用 FreeString 方法。
这是从 FreePascal DLL 与 Delphi EXE 交换字符串的最佳方式吗?我可以避免从 Delphi 调用 FreeString 吗?
最后,如果这是正确的解决方案,默认情况下它在 Delphi 2010 和 WideString 中的表现如何:我是否也需要在 FreePascal 中强制使用 WidePChar?
最佳答案
在 DLL 和 Delphi 应用程序之间交换字符串而不使用 FreeString
调用的一种方法是从调用应用程序中获取字符串缓冲区作为 PChar
,并填充DLL 中的缓冲区。这就是 Windows API 函数在需要与调用应用程序交换字符串时的工作原理。
为此,您的调用应用程序创建一个字符串缓冲区,并将引用该缓冲区的 PChar
以及缓冲区大小发送到您的 DLL 函数。如果缓冲区大小小于 DLL 必须发送到应用程序的实际字符串,则 DLL 函数可以将缓冲区实际所需的大小发送到调用应用程序。
how will it behave with Delphi 2010 and the WideString by default: do I need to force WidePChar in FreePascal too ?
在 Delphi 2009 和 Delphi 2010 中,PChar
等于 PWideChar
。在以前版本的 Delphi 中,据我所知,在 FreePascal 中,PChar
等于 PAnsiChar
。因此,如果您从 DLL 返回 PChar
,您的代码将无法在 Delphi 2010 中正常工作。您应该显式使用 PAnsiChar
或 PWideChar
。您可以再次遵循 Windows API 函数的模式:它们几乎为每个 API 函数提供两个版本 - 一个支持 WideChar
,其名称以 W 字符作为后缀,另一个版本支持 AnsiChar
,其名称以 A 字符作为后缀。
您的 DLL 函数声明将如下所示:
function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean;
function AStringFuncA(Buffer: PAnsiChar; var BufferSize: Integer): Boolean;
编辑:
这里是一个示例代码:
WideChar
的 DLL 函数将如下所示:function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall; var MyOutputStr : WideString; begin Result := False; // Calculate your output string here. MyOutputStr := 'This is a sample output'; // Check if buffer is assigned, and its given length is enough if Assigned(Buffer) and (BufferSize >= Length(MyOutputStr) + 1) then begin // Copy output string into buffer StrPCopy(Buffer,MyOutputStr); Result := True; end; // Return actual size of output string. BufferSize := Length(MyOutputStr) + 1; end;
对于
AnsiChar
版本,您使用PAnsiChar
作为参数,并使用几乎相似的代码以AnsiString
作为变量,或者转换参数到PWideChar
并在AStringFuncA
函数中调用您自己的AStringFuncW
,其结果将转换回PAnsiChar
。以下是如何在接口(interface)单元中定义这些函数以供 DLL 客户端使用:
unit TestDLLIntf; interface const TestDll = 'Test.dll'; function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall; function AStringFuncA(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall; function AStringFunc(Buffer: PWideChar; var BufferSize: Integer): Boolean; stdcall; implementation function AStringFuncW; external TestDll name 'AStringFuncW'; function AStringFuncA; external TestDll name 'AStringFuncA'; {$IFDEF UNICODE} function AStringFunc; external TestDll name 'AStringFuncW'; {$ELSE} function AStringFunc; external TestDll name 'AStringFuncA'; {$ENDIF} end.
在上面的代码中,
AStringFuncW
和AStringFuncA
函数都被声明为外部函数。AStringFunc
函数在 Delphi 2009 或 2010 中引用WideChar
版本,在旧版本中引用AnsiChar
。在这里您可以看到 DLL 客户端如何使用您的函数:
procedure TForm1.Button1Click(Sender: TObject); var Str : string; Size : Integer; begin // Retrieve required buffer size AStringFunc(nil,Size); // Set buffer SetLength(Str,Size); // Retrieve output string from DLL function. if AStringFunc(PChar(Str),Size) then ShowMessage(Str); end;
在上面的代码中,客户端应用程序首先从
AStringFunc
获取实际输出大小,然后设置字符串缓冲区,并从DLL中检索输出字符串。请注意,相同的代码应该适用于 Unicode 和非 Unicode 版本的 Delphi,因为AStringFunc
引用 DLL 内的AStringFuncA
或AStringFuncW
,具体取决于您的编译器是否支持 Unicode。
关于delphi - 在 Freepascal 编译的 DLL 和 Delphi 编译的 EXE 之间交换字符串 (PChar),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2638652/