Exchanging strings (PChar) between a Freepascal compiled DLL and a Delphi compiled EXE

前端 未结 3 1540
名媛妹妹
名媛妹妹 2020-12-30 16:13

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 cod

3条回答
  •  执念已碎
    2020-12-30 16:36

    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.

提交回复
热议问题