我如何从 DLL 传递 pchar?dll 必须与其他应用程序兼容,而不仅仅是 delphi。在帮助中写道,将指针传递给局部变量是危险的,如果我们将此变量设为全局变量,则代码将不是线程安全的。
我们可以安全地传递一个宽字符串,但在这种情况下,dll 将与其他(非 Delphi)应用程序不兼容。
{code in dll}
function Test:pchar;
var
str:string;
begin
str:='Some string';
result:=pchar(str); // wrong way, may be UB.
end;
{code in dll}
var
str:string // global variable
function Test:pchar;
begin
str:='Some string';
result:=pchar(str); // code not threadsafe
end;
{code in dll}
function Test:WideString;
var
str:WideString;
begin
str:='Some string';
result:=str; // will works ONLY with Delphi apps :(
end;
:(
how do experienced programmers?
var
Form1: TForm1;
function Test(out p:pchar):Integer;stdcall; external 'project2';
procedure FinalizeStr(P:Pointer);stdcall; external 'project2';
implementation
{$R *.dfm}
function StrFromDll:string;
var
p:pchar;
begin
try
setstring(result,P, test(p));
finally
finalizestr(cardinal(p));
end;
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
showmessage(strfromdll);
end;
{code in dll}
library Project2;
uses
fastmm4,fastmm4messages,
SysUtils,
Classes;
{$R *.res}
function Test(out p:pchar):Integer;stdcall;
var
str:string;
len:integer;
begin
str:='Hello, i am a string from the dll?!#@%!?'+inttostr(hinstance); // only for example
len:=length(str);
p:=allocmem(len+1);
StrPLCopy(P,str,len);
result:=len;
end;
procedure FinalizeStr(P:Pointer);stdcall;
begin
FreeMem(P);
end;
exports Test,FinalizeStr;
end.
Run Code Online (Sandbox Code Playgroud)
您有三个主要选择。
让调用者分配被调用者填充的内存
function GetString(Buffer: PWideChar; BufferLen: Integer): Integer; stdcall;
Run Code Online (Sandbox Code Playgroud)
调用者必须知道要分配多少内存。您可以通过安排函数返回复制的字符数,或者,如果Buffer是nil,所需的缓冲区大小来实现这一点。所以调用者可能会像这样调用这个函数:
var
str: string;
....
SetLength(str, GetString(nil, 0) - 1);
GetString(PChar(str), Length(str) + 1);
Run Code Online (Sandbox Code Playgroud)
该-1和+1是应对空终止符。
让被调用者分配内存,并导出一个释放器
看起来像这样:
function GetString: PWideChar; stdcall;
function Free(P: Pointer); stdcall;
Run Code Online (Sandbox Code Playgroud)
被调用者从其内部堆分配内存。但是被调用者还必须导出一个释放内存的函数。调用序列如下所示:
var
P: PWideChar;
str: string;
....
P := GetString();
str := P;
Free(P);
Run Code Online (Sandbox Code Playgroud)
对此的一个转折是分配共享堆,例如 COM 堆。这样你就不需要导出释放分配器,因为调用者可以在没有你帮助的情况下获得 COM 堆释放分配器。
返回一个 COM 字符串
COMBSTR是从共享 COM 堆分配的,任何 Windows 开发环境都可以使用这些对象。Delphi 将这些包装为WideString. 但有一点不同,Delphi ABI 与其他工具不同,您不能将其WideString用作函数返回值并与其他工具互操作。相反,您应该使用 out 参数。
procedure GetString(out str: WideString); stdcall;
Run Code Online (Sandbox Code Playgroud)
更多详细信息:为什么不能将 WideString 用作互操作的函数返回值?
| 归档时间: |
|
| 查看次数: |
2507 次 |
| 最近记录: |