Delphi 在主机应用程序和DLL之间传递包含记录的方法
是否可以(不使用运行时包或共享内存DLL)在主机应用程序和DLL模块之间传递记录类型,其中记录类型包含函数/过程(Delphi 2006及以上版本) 为了简单起见,让我们假设我们的记录类型不包含任何字符串字段(因为这当然需要Sharemem 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):
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;