我希望为用户添加用于将插件编写到我在Delphi中开发的程序的功能.该程序是单个可执行文件,没有使用DLL.
这将允许用户社区编写我的程序的扩展来访问内部数据并添加他们可能觉得有用的功能.
我看过帖子:添加插件功能的建议?但它的答案似乎无法转移到Delphi程序.
我希望,如果可能的话,添加此功能并将我的应用程序保留为单个可执行文件,而不需要任何DLL或其他模块.
您是否知道任何建议如何在Delphi中做到最好的资源,组件或文章,或者您有自己的建议吗?
我要问的第一个问题是,您是否需要插件来访问主机应用程序的UI,或者添加自己的任何UI元素?或者插件是否仅限于查询和/或向主机应用程序提供数据?
后者更容易,并开辟了两种可能性.其他人已经提到了DLL,这是第一种方法.某些警告适用 - 通常,您应该仅使用Windows API中使用的数据类型与dll连接.这样你可以确定插件DLL将理解你的数据类型,无论它们是在什么语言/编译器中创建的.(例如,使用PChars,而不是字符串.不要通常将Delphi类如TStream传递给这在某些情况下似乎有效,但一般来说不安全,因为即使DLL是在Delphi中编译的,它也可能是编译器的不同版本,对TStream的概念略有不同).谷歌在Delphi中使用DLL,你会发现更多的提示.
另一种尚未提及的方法是在应用程序本身中启用脚本.有几个非常强大的第三方脚本引擎,包括商业和免费,其中大多数允许您使用脚本交换Delphi对象.其中一些库仅支持Pascal作为脚本语言,其他库将允许您使用Basic(可能更适合初学者用户)或其他语言.请参阅http://www.remobjects.com/free.aspx上的 RemObjects Pascal Script(免费).
我最喜欢的脚本解决方案是来自http://mmm-experts.com/Products.aspx?ProductID=3的 Python for Delphi(P4D,也是免费的)它可以通过RTTI与您的课程完美地连接,并允许您执行Delphi应用程序中的Python代码,以及Python脚本中的Delphi类.鉴于Python的流行,如果您想吸引开发人员加入您的项目,这可能是一个可行的解决方案.但是,每个用户都需要安装Python发行版.
在我看来,从潜在插件编写者的角度来看,如果你使用脚本而不是你选择DLL,那么进入门槛会降低.
现在,回到我最初的问题:如果您需要插件与您的用户界面进行交互,例如通过在其上放置控件,事情会变得复杂得多.通常,DLL不能用于执行此操作.Borland/CodeGear认可的方法是使用包(BPL).使用BPL,您可以访问和实例化插件提供的类,就像它们在主机应用程序中声明一样.问题是,所有BPL必须使用与主应用程序相同的Delphi版本和版本进行编译.在我看来,这使得包完全不切实际,因为很难期望全世界所有潜在的插件编写者都会使用相同版本的Delphi.一个主要的陷阱.
为了解决这个问题,我尝试了一种不同的方法:继续使用DLL,并为插件开发语法来描述它所需的UI,然后在主机应用程序中自己创建UI.(XML是一种表达UI的便捷方式,因为您可以免费获得父母/嵌套的概念.)UI描述语法可以包括在控件的内容或状态发生变化时触发的DLL回调.但是,此方法会将插件限制为应用程序已使用或已注册的VCL控件集.而且这不是一个更蠢的工作,而BPL肯定是.
谷歌也为"Delphi插件框架".有一些现成的解决方案,但据我所知,他们通常使用BPL,其用途有限.
实际上,你引用的问题的公认答案对Delphi来说也是合适的.您的插件将是DLL,您可以指示他们应该导出具有特定名称和签名的函数.然后,您的程序将加载DLL(with LoadLibrary
)并获取函数的地址(with GetProcAddress
).如果DLL未加载,或者该函数不存在,则DLL不是应用程序的插件.
获得DLL的地址后,可以调用它.您可以将函数接口传递给代表您希望公开的应用程序部分的内容.您还可以要求该函数返回一个接口,该接口具有应用程序将在不同时间调用的方法.
在测试插件系统时,用Delphi以外的语言编写插件是明智的.这样,您就可以更自信地无意中要求每个人都使用Delphi.
起初我去了BPL和DLL基础插件.并发现他们难以保持.
如果您使用BPL系统,则需要将BPL版本与EXE版本匹配.这包括可能破坏某些东西的Delphi更新.我发现(困难的方法)如果我需要在每个版本中包含我的所有插件,那么根本就没有插件.
然后我切换到普通的DLL插件.但该系统只是复杂的代码库.这不是一件好事.
在破解网络的同时,我发现了Lua嵌入式脚本语言,并随之提供.Lua是150K DLL,嵌入字节码编译器,解释器和非常简单和智能的动态编程语言.
我的插件是简单的lua脚本.容易保持和制作.有预制的Delphi示例,因此您可以将任何类或过程导出为Lua表或函数.GUI与否.例如,我在我的应用程序中使用TurboPower Abbrevia进行压缩.我将我的压缩类导出到lua,所有插件现在都可以调用zip(' . ','dir.zip')和unzip().然后我切换到7zip并且只实现了旧类来使用7zip.所有插件都像他们一样工作,支持新的zip(' . ','dir.7z').
我创建了TLuaAction,它从脚本中调用Execute(),Update(),Hint()过程.
Lua allso拥有自己的插件系统,可以轻松添加功能.例如,luacom make易于使用COM自动化,luainterface允许从lua调用.net.有关更多信息,请参阅luaforge.在Delphi中有Lua IDE,有源代码.
我不久前试图概述所有这些选项.我和读者/评论者一起建立了这个清单:
从程序加载的DLL/BPL.
从沙箱加载的DLL/BPL(可以是程序的另一个副本或专用的"服务器"应用程序,并通过消息/套接字/ msmq /命名管道/邮件槽/内存映射文件与主程序通信).
COM(任何变体).
DDE(请不要).
通过标准输入/输出进行通信的外部程序.
通过文件进行通信的外部程序(文件名是程序的参数).
通过drop文件夹工作的外部程序(对批处理很有用).
与windows消息/ windows sockets/msmq /命名管道/邮件槽/内存映射文件/数据库发布 - 订阅通信的外部程序.