在Freepascal编译DLL和Delphi编译的EXE之间交换字符串(PChar) [英] Exchanging strings (PChar) between a Freepascal compiled DLL and a Delphi compiled EXE

查看:339
本文介绍了在Freepascal编译DLL和Delphi编译的EXE之间交换字符串(PChar)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

经过大量的实验,我发现了一种从FreePascal编译DLL与Delphi编译的EXE交换PChar的方法。我负责DLL和EXE源代码,但一个必须在FreePascal中,另一个在Delphi中。我的解决方案涉及DLL中的以下方法:

  function GetAString():PChar; 
var aString:string;
begin
aString:='我的字符串';
result:= StrAlloc(length(aString)+ 1);
StrPCopy(result,aString);
结束

程序FreeString(aString:PChar);
begin
StrDispose(aString);
结束

从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函数在需要与调用应用程序交换字符串时的工作原理。



为此,您的调用应用程序将创建一个字符串缓冲区,并发送一个PChar那个缓冲区以及你的DLL函数的缓冲区大小。如果缓冲区大小小于实际的字符串DLL必须发送到应用程序,您的DLL函数可以将缓冲区的实际所需大小发送给调用应用程序。


它将如何在Delphi 2010
和WideString默认情况下表现:我需要
需要强制WidePChar在FreePascal
吗?


在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; 

函数AStringFuncA(缓冲区:PAnsiChar; var BufferSize:Integer):Boolean;

编辑:



这是一个示例代码:



1-你的DLL功能的宽带将是这样的:

  function AStringFuncW(Buffer:PWideChar; var BufferSize:Integer):Boolean;标准
var
MyOutputStr:WideString;
begin
结果:= False;

//在此处计算输出字符串。
MyOutputStr:='这是一个示例输出';

//检查是否分配缓冲区,其给定长度足够
如果分配(缓冲区)和(缓冲区大小> =长度(MyOutputStr)+ 1)则
开始
//将输出字符串复制到缓冲区
StrPCopy(Buffer,MyOutputStr);
结果:= True;
结束
//返回输出字符串的实际大小。
BufferSize:= Length(MyOutputStr)+ 1;
结束

对于AnsiChar版本,您可以使用与AnsiString和PAnsiChar相同的代码,或转换ANSI字符串参数到Unicode,并在AStringFuncA函数内调用AStringFuncW,然后将返回字符串从AStringFuncW转换为PAnsiChar。



2-这里是如何在界面中定义这些函数单位由您的DLL客户端使用:

  unit TestDLLIntf; 

接口
const
TestDll ='Test.dll';

函数AStringFuncW(缓冲区:PWideChar; var BufferSize:Integer):Boolean;标准
函数AStringFuncA(缓冲区:PWideChar; var BufferSize:Integer):Boolean;标准
function AStringFunc(Buffer:PWideChar; var BufferSize:Integer):Boolean;标准

实现

函数AStringFuncW;外部TestDll名称AStringFuncW;
函数AStringFuncA;外部TestDll名称AStringFuncA;
{$ IFDEF UNICODE}
函数AStringFunc;外部TestDll名称AStringFuncW;
{$ ELSE}
函数AStringFunc;外部TestDll名称AStringFuncA;
{$ ENDIF}

结束。

在上述代码中,AStringFuncW和AStringFuncA函数都被声明为外部函数。 AStringFunc函数是指Delphi 2009 - 2010中的WideChar版本,并且在其他版本中引用了AnsiChar版本。



3-这里您可以看到您的DLL客户端如何使用您的功能:

  procedure TForm1.Button1Click(Sender:TObject); 
var
Str:string;
大小:整数;
begin
//检索所需的缓冲区大小
AStringFunc(nil,Size);
//设置缓冲区
SetLength(Str,Size);
//从DLL函数检索输出字符串。
如果AStringFunc(PChar(Str),Size)then
ShowMessage(Str);
结束

在上述代码中,客户端应用程序首先从AStringFunc获取实际的输出大小,然后设置一个字符串缓冲区,并从DLL检索输出字符串。请注意,相同的代码应该在Unicode和非Unicode版本的Delphi中使用,因为AStringFunc在DLL中指向AStringFuncA或AStringFuncW,具体取决于编译器是否支持Unicode。


After a lot of experimentations, I found a way to exchange PChar from a FreePascal compiled DLL with a Delphi compiled EXE. I'm in charge of both the DLL and EXE source code but one MUST BE in FreePascal and the other one in Delphi. My solution involves the following methods in the 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;

And from the Delphi EXE, to call the GetAString method, I need to Call the GetAString method, save the PChar to an actual Delphi String and call the FreeString method.

Is this the best way of exchanging a string from a FreePascal DLL with a Delphi EXE ? Can I avoid the call to FreeString from Delphi ?

And finally, if that's the correct solution, how will it behave with Delphi 2010 and the WideString by default: do I need to force WidePChar in FreePascal too ?

解决方案

One way to exchange strings between your DLL and Delphi application without using FreeString call is to take string buffer from the calling application as a PChar, and fill the buffer in the DLL. That is how Windows API functions work when they need to exchange strings with calling applications.

To do so, your calling application creates a string buffer, and sends a PChar referring to that buffer along with buffer size to your DLL function. If buffer size is smaller than the actual string DLL has to send to the application, your DLL function can send the actual required size for the buffer to the calling application.

how will it behave with Delphi 2010 and the WideString by default: do I need to force WidePChar in FreePascal too ?

In Delphi 2009 and Delphi 2010, PChar equals to PWideChar. In previous versions of Delphi, and as far as I know, in FreePascal, PChar equals to PAnsiChar. So If you return PChar from your DLL, your code won't work correctly in Delphi 2010. You Should explicitly use PAnsiChar or PWideChar. You can again follow Windows API functions. They provide two versions of many API functions, one with WideChar support which its name has a W character as a suffix, and the other one with ANSI support which its name has an A character as a suffix.

Your DLL function declaration would be something like this:

function AStringFuncW(Buffer: PWideChar; var BufferSize: Integer): Boolean;

function AStringFuncA(Buffer: PAnsiChar; var BufferSize: Integer): Boolean;

EDIT:

Here is a sample code:

1- Your DLL function for widechar would be like this:

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;

For AnsiChar version, you can use either the same code with AnsiString and PAnsiChar, or convert the ANSI string parameter to Unicode, and call AStringFuncW inside your AStringFuncA function, then convert the return string from AStringFuncW to PAnsiChar.

2- Here is how you can define these functions in your interface unit to be used by your DLL clients:

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.

In the above code, both AStringFuncW and AStringFuncA functions are declared as external functions. AStringFunc function refers to WideChar version in Delphi 2009 - 2010, and refers to AnsiChar version in other versions.

3- Here you can see how your DLL clients can use your function:

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;

In the above code, client application first gets actual output size from AStringFunc, then sets a string buffer, and retrieves output string from DLL. Take note that the same code should work in both Unicode and Non-Unicode versions of Delphi, because AStringFunc refers to either AStringFuncA or AStringFuncW inside your DLL depending on whether your compiler supports Unicode or not.

这篇关于在Freepascal编译DLL和Delphi编译的EXE之间交换字符串(PChar)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆