Passing a record containing a method between the host application and the DLL

Is it possible (without using Runtime packages or DLLs with shared memory) to transfer the record type between the host application and the DLL module, where the record type contains functions / procedures (Delphi 2006 and higher)?

For simplicity, suppose that our record type does not contain any string fields (since this, of course, requires the Sharemem DLL), and here is an example:

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

So, to say this simply: can I pass an β€œinstance” of TMyRecord between the host application and the DLL (in any direction) without using Runtime Packages or the shared memory DLL and execute the DoSomething function from both the host EXE and the DLL?

+4
source share
2 answers

If I understood your question correctly, you can do it, here is 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 the application and the dll, the unit in which your fantastic entry 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, the test application, the application file β†’ new β†’ vcl forms, release the button in the form, include uCommon.pas in the uses clause, add a link to the external method

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

and in the button on the click event add

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

RENOUNCEMENT:

  • works in D2010;
  • compiles on my machine!

enjoy it!


David Heffernan's edit

To be 100% understandable, the DoSomething method that is executed is the method defined in the DLL. The DoSomething method defined in EXE is never executed in this code.


+4
source

I would not suggest whether this works or not. If you need a DLL to work with instances of TMyRecord , the safest option would be to use regular DLL export functions instead, for example:

DLL:

 type TMyRecord = record Field1: Integer; Field2: Double; end; function DoSomething(var ARec: TMyRecord; AValue1: Integer; AValue2: Double): Boolean; stdcall; begin ... end; exports DoSomething; end. 

applications:

 type TMyRecord = record Field1: Integer; Field2: Double; end; function DoSomething(var ARec: TMyRecord; AValue1: Integer; AValue2: Double): Boolean; stdcall; external 'My.dll'; procedure DoSomethingInDll; var Rec: TMyRecord; //... begin //... if DoSomething(Rec, 123, 123.45) then begin //... end else begin //... end; //... end; 
+7
source

Source: https://habr.com/ru/post/1385266/


All Articles