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.