delphidllrecordshared-memoryruntime-packages

Passing a method-containing record between host application and DLL


Is it possible (without the use of Runtime Packages or the Shared Memory DLL) to pass a Record type between the host application and a DLL module where the Record type contains Functions/Procedures (Delphi 2006 and above)?

Let's presume for the sake of simplicty that our Record type doesn't contain any String fields (as this of course requires the Sharemem DLL), and here's an example:

TMyRecord = record
  Field1: Integer;
  Field2: Double;
  function DoSomething(AValue1: Integer; AValue2: Double): Boolean;
end;

So, to state this simply: can I pass an "instance" of TMyRecord between the host application and a DLL (in either direction), without the use of Runtime Packages or Shared Memory DLL, and execute the DoSomething function from both the Host EXE and the DLL?


Solution

  • If I understood your question correctly, then you can do it, here's one way to do it:

    testdll.dll

    library TestDll;
    
    uses
      SysUtils,
      Classes,
      uCommon in 'uCommon.pas';
    
    {$R *.res}
    
    procedure TakeMyFancyRecord(AMyFancyRecord: PMyFancyRecord); stdcall;
    begin
      AMyFancyRecord^.DoSomething;
    end;
    
    exports
      TakeMyFancyRecord name 'TakeMyFancyRecord';
    
    begin
    end.
    

    uCommon.pas <- used by both application and dll, unit where your fancy record is defined

    unit uCommon;
    
    interface
    
    type
      PMyFancyRecord = ^TMyFancyRecord;
      TMyFancyRecord = record
        Field1: Integer;
        Field2: Double;
        procedure DoSomething;
      end;
    
    implementation
    
    uses
      Dialogs;
    
    { TMyFancyRecord }
    
    procedure TMyFancyRecord.DoSomething;
    begin
      ShowMessageFmt( 'Field1: %d'#$D#$A'Field2: %f', [ Field1, Field2 ] );
    end;
    
    end.
    

    and finally a test application, file -> new -> vcl forms application, drop a button on the form, include uCommon.pas in the uses clause, add reference to external method

    procedure TakeMyFancyRecord(AMyFancyRecord: PMyFancyRecord); stdcall;
      external 'testdll.dll' name 'TakeMyFancyRecord';
    

    and in the button's on click event, add

    procedure TForm1.Button1Click(Sender: TObject);
    var
      LMyFancyRecord: TMyFancyRecord;
    begin
      LMyFancyRecord.Field1 := 2012;
      LMyFancyRecord.Field2 := Pi;
      TakeMyFancyRecord( @LMyFancyRecord );
    end;
    

    DISCLAIMER:

    enjoy!


    David Heffernan' edit

    Just to be 100% clear, the DoSomething method that is executed is the method defined in the DLL. The DoSomething method defined in the EXE is never executed in this code.