The rule of thumb for allocating/deallocating memory in EXE and DLL is: the module that allocates memory is responsible for deallocation the same memory. In your example it is DLL who allocates and deallocates memory, so it is correct.
There is one exception from the general rule. Both Delphi and the latest Free Pascal versions implement WideStrings as BSTR - a string data type that is used by COM. WideStrings are allocated and freed by Windows, not by Delphi (or Free Pascal) memory manager. So there is no need to use PWideChar to pass WideString arguments between EXE and DLL - WideStrings can be passed directly.
Updated:
I have tested the following code:
Free Pascal (version 2.2.4) DLL:
library TestLib1;
{$mode objfpc}{$H+}
{$IFDEF WINDOWS}{$R TestLib1.rc}{$ENDIF}
procedure GetAStringProc(var S: WideString); stdcall;
begin
S:= '12345';
end;
function GetAStringFunc: WideString; stdcall;
begin
Result:= '12345';
end;
exports
GetAStringProc, GetAStringFunc;
begin
end.
Delphi 2009 EXE (main form):
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Button2: TButton;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
S: WideString;
end;
var
Form1: TForm1;
type
TGetAStringProc = procedure(var S: WideString); stdcall;
TGetAStringFunc = function: WideString; stdcall;
var
GetAStringProc: TGetAStringProc;
GetAStringFunc: TGetAStringFunc;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
GetAStringProc(S);
Caption:= S;
S:= '';
end;
procedure TForm1.Button2Click(Sender: TObject);
begin
S:= GetAStringFunc;
Caption:= S;
S:= '';
end;
procedure TForm1.FormCreate(Sender: TObject);
var
LibHandle: THandle;
begin
LibHandle:= LoadLibrary('TestLib1.dll');
if LibHandle <> 0 then begin
@GetAStringProc:= GetProcAddress(LibHandle, 'GetAStringProc');
@GetAStringFunc:= GetProcAddress(LibHandle, 'GetAStringFunc');
end;
if not Assigned(GetAStringProc) or not Assigned(GetAStringFunc) then
ShowMessage('Error!');
end;
end.
It appeared that the procedure GetAStringProc works fine while the function GetAStringFunc leads to access violation. Delphi and Free Pascal seems to return the string-type result differently.