How i can pass pchar from the DLL? dll must be compatible with other apps, not just delphi. In help is written that it is dangerous to pass pointers to local variables, if we make this variable global, the code will not be thread-safe.
We can safely pass a wide string,but in this case, the dll will not be compatible with other (non-Delphi) apps.
{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.
You have three main options.
Have the caller allocate memory that the callee populates
The caller has to know how much memory to allocate. You can do this by arranging the the function returns the number of characters copied, or, if
Bufferisnil, the size of buffer required. So the caller might call this function like this:The
-1and+1are to deal with the null-terminator.Have the callee allocate memory, and export a deallocator
That looks like this:
The callee allocates the memory off its internal heap. But the callee also has to export a function that frees the memory. The call sequence looks like this:
A twist on this is to allocate off a shared heap, for instance the COM heap. That way you don't need to export a deallocator since the caller can obtain the COM heap deallocator without your help.
Return a COM string
The COM
BSTRis allocated off the shared COM heap, and any Windows development environment can work with these objects. Delphi wraps these asWideString. A twist though is that the Delphi ABI differs from other tools and you cannot useWideStringas a function return value and interop with other tools. Instead you should use an out parameter.More details here: Why can a WideString not be used as a function return value for interop?