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

Delphi 在主机应用程序和DLL之间传递包含记录的方法,delphi,dll,record,shared-memory,runtime-packages,Delphi,Dll,Record,Shared Memory,Runtime Packages,是否可以(不使用运行时包或共享内存DLL)在主机应用程序和DLL模块之间传递记录类型,其中记录类型包含函数/过程(Delphi 2006及以上版本) 为了简单起见,让我们假设我们的记录类型不包含任何字符串字段(因为这当然需要Sharemem DLL),下面是一个示例: TMyRecord = record Field1: Integer; Field2: Double; function DoSomething(AValue1: Integer; AValue2: Double):

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

为了简单起见,让我们假设我们的记录类型不包含任何字符串字段(因为这当然需要Sharemem DLL),下面是一个示例:

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

因此,简单地说:我可以在不使用运行时包或共享内存DLL的情况下,在主机应用程序和DLL之间(在任意方向)传递TMyRecord的“实例”,并从主机EXE和DLL执行DoSomething函数吗?

我不建议这样做,不管它是否有效。如果需要DLL在
TMyRecord
实例上操作,最安全的选择是使用DLL导出普通函数,例如:

动态链接库:

应用程序:


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

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新建->vcl表单应用程序,在表单上放置一个按钮,在uses子句中包含uCommon.pas,添加对外部方法的引用

procedure TakeMyFancyRecord(AMyFancyRecord: PMyFancyRecord); stdcall;
  external 'testdll.dll' name 'TakeMyFancyRecord';
在按钮的点击事件中,添加

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

  • D2010工程
  • 在我的机器上编译
享受吧


大卫·赫弗南编辑

要100%清楚,执行的DoSomething方法是DLL中定义的方法。此代码中从未执行EXE中定义的DoSomething方法



遗憾的是,在这种情况下,这是不可能的,因为记录必须同时包含方法和类运算符才能按预期运行。除此之外,通常这是我的建议(也是我自己的建议)。+1我也不建议这样做,因为将来我们不知道它会得到多大程度的支持,但问题是它是否可能。。。另外,我不知道“record方法”是如何处理的,但我假设这只是编译器的魔法,也就是说,当你调用“record方法”时,它只调用一个方法,在这个方法中它将记录作为第一个/最后一个参数传递,其余的都是该方法的参数。。。当然,我可能是错的。另一个缺点是,它需要在DLL和EXE中驻留相同的方法代码。您不能在EXE中实现该方法并让DLL直接调用它,反之亦然。您需要一个VMT才能工作,而这些记录没有AFAIK。如果代码发生更改,则必须重新编译EXE和DLL以保持同步。您可以传递第二条记录,其中包含在需要时传递主记录的函数指针。这将允许您集中代码,以便只有EXE或DLL是直接访问方法的,并充当另一个模块的代理。“记录必须同时包含方法和类运算符才能正常工作。”请注意,您接受的答案不符合此标准。当您将记录发送到另一个模块时,您发送的是数据,而不是代码。@dorin如果dll和exe同步更新,则无所谓。目前还不清楚具体要求是什么。这就是为什么我在你的回答中添加了澄清。就我个人而言,我会使用一个界面。感谢您为我测试:)+1并标记为正确答案!使用指向记录的指针对行为没有影响。您也可以使用普通值参数、常量参数等@DavidHeffernan是的,谢谢,但是给猫剥皮的方法不止一种!(:我的意思是,你的回答暗示了使用指向记录的指针有一些特殊之处。没有。嗯,是的,直到5分钟后才知道你也可以使用“const param”编译器发挥了神奇的作用。我怀疑您希望同时向DLL传递数据和代码。正确的方法是使用接口。您接受的答案不是传递代码,而是传递数据。大卫:DLL和EXE共享一个包含记录类型的公共单元……在Dorin完成的测试用例中,是从主机executabl传递的记录e到DLL允许DLL执行“DoSomething”方法,因此他的解决方案完全符合我的需要。通常我同意接口是可行的,但由于这与我正在处理的“智能类型”有关,我需要能够在主机和DLL之间传递记录本身(现在我可以了)。谢谢:)只是为了让您知道执行的方法是DLL中的方法,即使记录是在EXE.Yup中创建的。。。知道这一点很好,但在本例中,这是期望的行为:)
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.
procedure TakeMyFancyRecord(AMyFancyRecord: PMyFancyRecord); stdcall;
  external 'testdll.dll' name 'TakeMyFancyRecord';
procedure TForm1.Button1Click(Sender: TObject);
var
  LMyFancyRecord: TMyFancyRecord;
begin
  LMyFancyRecord.Field1 := 2012;
  LMyFancyRecord.Field2 := Pi;
  TakeMyFancyRecord( @LMyFancyRecord );
end;