在主机应用程序和DLL之间传递包含方法的记录

LaK*_*ven 5 delphi dll record shared-memory runtime-packages

是否可以(不使用运行时包或共享内存DLL)在主机应用程序和DLL模块之间传递Record类型,其中Record类型包含函数/过程(Delphi 2006及更高版本)?

让我们假设为了简单起见我们的Record类型不包含任何String字段(因为这当然需要Sharemem DLL),这里是一个例子:

TMyRecord = record
  Field1: Integer;
  Field2: Double;
  function DoSomething(AValue1: Integer; AValue2: Double): Boolean;
end;
Run Code Online (Sandbox Code Playgroud)

因此,简单地说明一下:我可以在主机应用程序和DLL(在任一方向)之间传递TMyRecord的"实例",而无需使用运行时包或共享内存DLL,并从主机EXE执行DoSomething功能和DLL?

Rem*_*eau 7

我不会建议,无论它是否有效.如果你需要DLL来操作TMyRecord实例,最安全的选择是让DLL导出普通函数,例如:

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.
Run Code Online (Sandbox Code Playgroud)

应用程序:

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; 
Run Code Online (Sandbox Code Playgroud)

  • "记录必须包含方法和类操作符以按预期运行." 请注意,您接受的答案不符合此标准.将记录发送到其他模块时,您发送数据而不是代码. (2认同)
  • @dorin如果dll和exe同步更新,那么无关紧要.目前尚不清楚其要求是什么.这就是为什么我在你的答案中加入了澄清的原因.就个人而言,我会使用一个界面. (2认同)

小智 4

如果我正确理解你的问题,那么你就可以做到,这是一种方法:

测试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.
Run Code Online (Sandbox Code Playgroud)

uCommon.pas <- 由应用程序和 dll 使用,定义您喜欢的记录的单元

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.
Run Code Online (Sandbox Code Playgroud)

最后是一个测试应用程序,文件 - >新建 - > vcl表单应用程序,在表单上放置一个按钮,在uses子句中包含uCommon.pas,添加对外部方法的引用

procedure TakeMyFancyRecord(AMyFancyRecord: PMyFancyRecord); stdcall;
  external 'testdll.dll' name 'TakeMyFancyRecord';
Run Code Online (Sandbox Code Playgroud)

并在按钮的单击事件中添加

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

免责声明:

  • 工作于D2010;
  • 在我的机器上编译!

享受!


大卫·赫弗南编辑

百分百明确的是,执行的 DoSomething 方法是 DLL 中定义的方法。EXE 中定义的 DoSomething 方法永远不会在此代码中执行。