很多性实验后,我发现从一个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和自由帕斯卡尔似乎以不同的方式返回字符串类型的结果。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top