一千萬個為什麽

搜索

在Freepascal編譯的DLL和Delphi編譯的EXE之間交換字符串(PChar)

經過大量的實驗,我找到了一種方法,用FreePascal編譯的DLL與Delphi編譯的EXE交換PChar。我負責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?

最佳答案

在不使用FreeString調用的情況下在DLL和Delphi應用程序之間交換字符串的一種方法是從調用應用程序中獲取字符串緩沖區作為PChar,並填充DLL中的緩沖區。這就是Windows API函數在需要與調用應用程序交換字符串時的工作方式。

為此,您的調用應用程序會創建一個字符串緩沖區,並向您的DLL函數發送一個引用該緩沖區的PChar以及緩沖區大小。如果緩沖區大小小於DLL必須發送到應用程序的實際字符串,則DLL函數可以將緩沖區的實際所需大小發送到調用應用程序。

Delphi 2010的表現如何?   和默認情況下的WideString:我   需要在FreePascal中強制使用WidePChar   呢?

在Delphi 2009和Delphi 2010中,PChar等於PWideChar。在以前版本的Delphi中,據我所知,在FreePascal中,PChar等於PAnsiChar。因此,如果從DLL返回PChar,則代碼將無法在Delphi 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,並在AStringFuncA函數內調用AStringFuncW,然後將返回字符串從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函數是指Delphi 2009 - 2010中的WideChar版本,並且在其他版本中引用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檢索輸出字符串。請註意,相同的代碼應該在Unicode和非Unicode版本的Delphi中都有效,因為AStringFunc在您的DLL中引用AStringFuncA或AStringFuncW,具體取決於您的編譯器是否支持Unicode。

轉載註明原文: 在Freepascal編譯的DLL和Delphi編譯的EXE之間交換字符串(PChar)