我阅读this article并发现虚拟库接口的概念很适合DLL的运行时加载。但是它们似乎不适用于Win32。这是真的?如果是这样:为什么?我不知道将这个想法与.NET结合起来会是什么。
编辑:我在这里大部分都是罗伯已经写过的。 :-)答案 0 :(得分:6)
在我看来,到目前为止,这三个答案完全错过了你的问题。那,或者我有。你问为什么Win32 Delphi没有像Hallvard的文章所说的神奇Supports
函数那样的东西,不是吗?即,给定DLL的名称和接口的类型信息的函数,返回使用从DLL导出的独立函数实现该接口的对象。
Hydra似乎都是关于从Win32程序调用.Net代码,而不是从DLL导入函数。 TJvPluginManager
要求插件DLL导出一个特殊的自注册函数,管理器在加载DLL时会调用该函数,并且该函数必须返回TJvPlugin
类的实例,因此插件在DLL中必须用Delphi或C ++ Builder编写。另一方面,Supports
函数适用于以任何语言编写的任何DLL。如果你愿意的话,你可以在kernel32上使用它。
我不知道为什么Win32 Delphi没有这样的东西。也许CodeGear没有看到太多的需求,因为Delphi和Turbo Pascal在没有它的情况下已经存在了很长时间。
编写一个类似的函数当然是可能的,我不认为它会比.Net版本更难编写,除非Microsoft的.Net库已经提供了大部分文件和Delphi将它们包装成一个方便的调用函数,看起来像Delphi多年来一直有的Supports
的其他几个重载版本。
在Win32中实现该功能会有几个步骤。 (我只提供了一个必要的草图,因为我现在还没有Delphi的运行副本。请问很好,也许我会找到更多细节。)首先,你需要确保类型接口的信息至少包含其方法的未修饰名称。然后,Supports
需要为接口中的每个方法生成一个函数存根(除了_AddRef,_Release和QueryInterface)。假设调用约定是stdcall
:
asm
// Pop the return address,
// discard the "this" pointer,
// and restore the return address
pop eax
pop ecx
push eax
jmp AddressOfFunction
end;
当Supports
生成每个存根时,它将填充实际的函数地址,从调用GetProcAddress
获取相应接口方法的名称。 stdcall
调用约定很容易包装; cdecl
有点麻烦; register
颈部疼痛。
一旦生成了所有存根,就需要生成一个看起来像是实现给定接口的“对象”。它不一定是实际的类。在编译时,Supports
不知道它将被要求实现的接口的布局,因此拥有一个类不会有太多成就。
最后一步是提供_AddRef
,_Release
和QueryInterface
的实现。 _AddRef
会不起眼; _Release
是您在引用计数达到零时调用FreeLibrary
的位置; QueryInterface
除了声称它支持IUnknown
以及提供给Supports
的界面外,根本不会做太多的事情。
Delphi过去常常带有一个示例程序,该程序演示了实现一个没有任何类的接口。这一切都是通过记录和函数指针完成的(毕竟这最终都是接口)。 Delphi还附带了相应的代码来实现类,这部分是为了说明Delphi可以做多少容易。我现在找不到演示程序的名称,但我确定它仍然在某处。
答案 1 :(得分:3)
此类功能有许多Win32选项。 Project JEDI有一个开源插件系统作为加载DLL或包的JVCL的一部分,并且可以包括表单和其他功能。
还有许多商业产品,包括TMS Plugin Framework和RemObjects Hydra。
答案 2 :(得分:1)
这不是什么新鲜事或特别事。这篇文章只谈论插件。本机代码已经能够做插件多年。关于P / Invoke的唯一特殊之处在于它允许本机代码和.NET在插件系统中相互通信,以及“可以将DLL视为实现接口的单个对象的小技巧”[这样]您可以使用Borland.Delphi.Win32单元中的Supports函数来检查DLL和所有方法是否可用。“
如果你想在Delphi for Win32中做文章的讨论,请查看LoadLibrary,GetProcAddress和FreeLibrary Windows API函数。如果你绝对必须有一个像文章描述的界面,你必须自己编写它,或者在DLL中(如果你自己编写DLL)通过编写返回接口的导出函数,或者在调用应用程序中,通过编写使用GetProcAddress动态创建接口的函数。 (注意:这需要用指针捣乱,并且通常比它的价值更麻烦。)
你最好的选择可能只是去做Sullivan所提到的:如果你只需要本机代码,可以使用JEDI VCL中的TJvPluginManager,或者如果你需要与.NET程序集通信,则使用Hydra。
答案 3 :(得分:0)
我自己使用Hydra作为仅支持Delphi的解决方案(即,没有与.NET接口),并且它也很适合。它更容易使用并增加了一些细节,但我认为它的基本实现方式与本文中详细描述的“自己动手”插件框架相同: http://www.saxon.co.uk/SinglePkg/
我会寻找一个基于界面的插件框架(如Hydra和上面段落中的“自己动手”系统),而不是仅仅在应用程序之间发送消息的插件框架。
sourceforge上有一个Delphi插件框架,不知道它是否与JEDI项目中的相同:http://sourceforge.net/projects/rd-dpf
还有其他一些商业解决方案,其中一个是Dragonsoft的: http://www.dragonsoft.us/products_dsps.php
答案 4 :(得分:0)
使用简单的com对象执行此操作有什么问题?声明所有插件实现的简单接口,并要求每个com对象都包含一个返回其类guid的导出函数。然后使用“插件”就像走过plugins目录一样简单,查找暴露特殊注册函数的DLL,调用它然后使用类guid然后调用com对象。
我在WIN32商业应用程序中使用了类似的东西并取得了巨大的成功。优点是我可以随意切换插件(当然提供应用程序没有运行以删除现有的插件),魔术全部在每个实现的接口中。