一个FreePascal的编译的DLL和一个Delphi编译EXE之间交换的字符串值(P Char)
-
26-09-2019 - |
题
很多性实验后,我发现从一个Delphi编译EXE一个FreePascal的编译DLL的方式来交换PChar类型。我负责的DLL和EXE文件的源代码,但必须在FreePascal的,另一个在德尔福。我的解决方案涉及在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字符串并调用FreeString方法。
这是用Delphi的EXE交换从FreePascal的DLL字符串的最好方法?我可以从德尔福避免调用FreeString?
最后,如果这是正确的解决方案,它将如何在默认情况下德尔福2010年和WideString的行为:我是否需要强制WidePChar在FreePascal的太
解决方案
单向到您的DLL和Delphi应用程序之间交换的字符串,而无需使用FreeString电话是采取从调用应用程序为PChar类型字符串缓冲区,并填写DLL中的缓冲。这是Windows API函数是如何工作的,当他们需要交流串与调用应用程序。
要做到这一点,你调用应用程序创建一个字符串缓冲区,并发送一个PChar类型指的是缓冲区,缓冲区大小为您的DLL函数一起。如果缓冲区大小比实际串DLL必须发送到应用程序时,你的DLL函数可以将实际需要的大小缓冲区来调用应用程序。
如何将与德尔福2010年表现 和WideString的默认:做我 需要强制WidePChar在FreePascal的 太?
在2009年的Delphi和Delphi 2010,PChar类型等于PWideChar。在Delphi的早期版本,而据我所知,在FreePascal的,PChar类型等于PAnsiChar。所以,如果你从DLL返回PChar类型,你的代码将无法正常工作在2010年德尔福你应该明确地使用PAnsiChar或PWideChar。您可以再次执行Windows API函数。它们提供的许多API函数,一个具有WideChar支持其它的名称具有W字元作为后缀,而另一个与ANSI支持其它的名称具有一个A字符作为后缀两个版本。
您的DLL函数的声明将是这样的:
function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean;
function AStringFuncA(Buffer: PAnsiChar; var BufferSize: Integer): Boolean;
修改强>
下面是一个示例代码:
1-对于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一致的版本,您可以使用相同的代码与AnsiString类型和PAnsiChar,或转换ANSI字符串参数为Unicode和呼叫AStringFuncW您AStringFuncA函数内部,然后从AStringFuncW转换返回的字符串来PAnsiChar。
2-下面是如何定义在接口单元这些功能由您的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功能是指WideChar版本在2009年的Delphi - 2010,和指的是属于ANSIChar版本在其他版本
3-在这里你可以看到你的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检索输出字符串。注意到,同样的代码应该在Delphi中的Unicode和非Unicode版本的工作,因为AStringFunc指的是AStringFuncA或AStringFuncW取决于你的编译器是否支持Unicode或不是你的DLL里面。
其他提示
根据哪些数据要传递,你可以使用WideStrings代替。他们被分配在Windows堆,所以如果你在DLL中分配一个和释放它的EXE他们都会经过同样的内存管理器。
您应该可以使用函数声明是这样的:
procedure GetAString(var Result: WideString); stdcall;
和Delphi和FreePascal的都将处理分配和自动释放。 WideString的是在同一个启用Unicode DELPHIS作为预统一的,所以你不会需要为这种变化的东西要么。
拇指用于分配/解除分配在EXE和DLL存储器的规则是:所述模块分配内存是负责解除分配相同的存储器。在你的榜样是谁DLL分配和释放内存,因此它是正确的。
有不同于一般规则一个例外。这两种Delphi和最新的Free Pascal版本实现WideStrings作为BSTR - 所使用的COM字符串数据类型。 WideStrings不受德尔福(或自由帕斯卡)的内存管理器分配和释放由Windows。所以没有必要使用PWideChar传递EXE和DLL之间WideString的参数 - 。WideStrings可以直接传递
更新:
我已经测试了以下代码:
免帕斯卡(版本2.2.4)DLL:
library TestLib1;
{$mode objfpc}{$H+}
{$IFDEF WINDOWS}{$R TestLib1.rc}{$ENDIF}
procedure GetAStringProc(var S: WideString); stdcall;
begin
S:= '12345';
end;
function GetAStringFunc: WideString; stdcall;
begin
Result:= '12345';
end;
exports
GetAStringProc, GetAStringFunc;
begin
end.
的Delphi 2009 EXE(主要形式):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
S: WideString;
end;
var
Form1: TForm1;
type
TGetAStringProc = procedure(var S: WideString); stdcall;
TGetAStringFunc = function: WideString; stdcall;
var
GetAStringProc: TGetAStringProc;
GetAStringFunc: TGetAStringFunc;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
GetAStringProc(S);
Caption:= S;
S:= '';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
S:= GetAStringFunc;
Caption:= S;
S:= '';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
LibHandle: THandle;
begin
LibHandle:= LoadLibrary('TestLib1.dll');
if LibHandle <> 0 then begin
@GetAStringProc:= GetProcAddress(LibHandle, 'GetAStringProc');
@GetAStringFunc:= GetProcAddress(LibHandle, 'GetAStringFunc');
end;
if not Assigned(GetAStringProc) or not Assigned(GetAStringFunc) then
ShowMessage('Error!');
end;
end.
看来该程序GetAStringProc正常工作而功能GetAStringFunc导致访问冲突。 Delphi和自由帕斯卡尔似乎以不同的方式返回字符串类型的结果。