Delphi应用程序的插件系统 - bpl和dll哪个更好?

23
我正在编写 Delphi 应用程序,需要具有加载插件的功能。我使用 JvPluginManager 作为插件系统/管理器 ;) 现在,在新的插件向导中,他们说最好使用 .bpl 类型的插件而不是 .dll 类型的插件...这种解决方案相对于 dll 类型的插件有什么优点?
到目前为止,我只发现了这种解决方案的缺点:
  1. 我必须将所有公共接口单元放在单独的包中,以便在加载插件时不会出现关于其他包中包含公共单元的错误

  2. 如果,假设,一个插件开发人员决定使用一些众所周知的单元(如 synapse),它默认没有运行时包,并且第二个插件开发人员也这样做,则“磕碰”...会在这里崩溃...

那么,相对于使用编译带有运行时包的 dll,使用 bpl 到底有哪些优点呢?
提前感谢您的回答
5个回答

18

BPL存在另一个缺点。当您切换Delphi版本时,您将不得不重新分发新的插件。在尝试找到完美的插件系统后,我最终选择了COM,并且从未后悔过这个决定。在一款商业应用程序中,其插件需求已超过8年,该应用程序仍在不断发展,但是一些随第一次迭代发布的插件仍以其原始形式存在。

如果您选择此方法,请自己办好事,并从简单的接口开始,然后再添加新接口。您不希望改变您的基本接口,因此保持简单而甜美。


你能提供关于如何实现基于COM的插件架构的更多信息吗? - Nick Hodges
基本原则是创建一个公共接口,然后创建实现该接口的COM自动化对象。父程序调用所需行为的特定COM自动化对象。我保留了可用插件和调用每个特定插件所需的唯一类GUID的单独查找。类GUID是针对单个自动化对象的,该对象还实现了公共插件接口。 - skamradt

9
如Alexander所说,BPL基本上是一个DLL。但有一些条件(摘自我做的一个不太短的总结:http://wiki.freepascal.org/packages):
  • 一个单元只能存在于BPL和Exe中一次。这避免了状态的重复(两次堆管理器和系统等全局变量,VMT表等)。
  • BPL只能使用其他BPL。
  • 这意味着动态类型(如ansistring和IS/AS)在BPL接口上可以正常工作。
  • 初始化/终止是单独的过程,它们的初始化顺序是严格控制的。对于静态动态加载,这更简单,对于动态加载(类似插件),所有对单元的依赖关系都会被检查。
  • 一切实质上都是一个大程序,这意味着BPL必须使用相同的编译器版本和RTL,并依赖于其他依赖项的版本。让.BPL插入现有的EXE可能更难,因为Delphi版本必须匹配。
  • 这也意味着您必须为插件.BPL依赖的非Delphi.BPL提供.dcp文件

简而言之:如果插件架构是开放的,请将其制作为DLL。否则,人们必须拥有完全相同的Delphi版本才能编写插件。

混合使用也是可能的。您自己和选定的开发人员的功能的更高级别的.BPL接口,以及其他人的底层过程DLL接口。

第三个选择是使用DLL,但指定Sharemem。字符串将起作用,多个Delphi版本将起作用。对象可以工作,但不安全(例如,我猜D2009与早期版本不起作用)。甚至其他语言的用户也可以通过COM进行分配,但并非完全排除非Delphi。


4
你的第一个缺点也是优点。如果在每个dll中复制共享代码,那么dll会变得越来越大。即使使用dll,您也可以通过将共享代码移动到单独的dll中来避免这种情况。
优点:
1.类型是共享的。没有 TFont 不是 TFont 的问题
2.内存管理器是共享的。字符串和类可以在插件之间作为参数使用,没有问题。
缺点:
1.插件只能使用 Delphi 或 BCB 构建。
2.插件应该使用相同的 Delphi 或 BCB 版本。
你考虑过使用 COM 吗?COM 使共享类型、字符串和类成为可能,而且插件可以用许多编程语言编写。

内存管理器(“no TFont is not a TFont error ;)”)也是共享的,如果你使用运行时“基础”包编译所有插件dll和应用程序,如rtl和vcl...那就不是重点。我的插件实际上没有共享任何代码,公共单元仅包含接口定义...所以这只是“使用共享bpls编译的dll与bpl插件”的问题;) - migajek
你关于使用运行时包构建dll是正确的。但是这样做也会有相同的缺点 :) - Lars Truijens
我不确定,但我认为微软已经弃用了COM和DCOM技术。 - Francis Lee
是的,据我所知,支持COM+,.NET基于它,并且与它们在很大程度上兼容。 - Marco van de Voort
1
在查看了Windows 7 Beta之后,我可以自信地说COM仍然没有被弃用,并且不会被弃用,因为仍然有一些Win的部分在内部使用COM。 - Yogi Yang 007

3

我对JvPluginManager不熟悉,但这取决于您如何使用BPL。

基本上,BPL只是一个普通的DLL,但它的初始化/终止工作从DllMain中剥离出来,分别由“Initialize”和“Finalize”函数执行。

因此,如果您像使用普通DLL一样使用BPL,则我所知道的唯一优点就是没有更多与DllMain相关的问题。那就是全部区别。

但在Delphi中,BPL还提供了一种方便的代码共享方式。这意味着有很多优势(公共内存管理器,无重复代码等等)。因此,通常的BPL做的事情比“只是DLL”多得多。

但这也意味着,现在您的插件系统仅限于Delphi(好吧,也可能是C ++ Builder)。即插件和exe必须在相同的编译器中编译才能平稳运行。

如果这对您可接受(即不使用MS Visual Studio),那么请继续使用BPL的所有功能。

P.S. 但如果您没有仔细设计接口端,升级此类BPL插件也可能成为噩梦。在某些最坏的情况下,您可能需要重新编译所有内容。

P.P.S. 正如我所说的:我不知道它如何应用于JvPluginManager创建的插件。


我已经决定放弃使用除Delphi以外的任何其他语言,因为我的接口正在使用一些Delphi特定的类型(例如TForm ;)) 即使是对于那些非常基本的对象,编写包装接口也需要太多时间了,超出了我的预算... - migajek
请注意 Delphi 版本问题。也许只有 Rad Studio 版本(BCB 和 Delphi 在同一版本中?)才能正常工作。它们可能必须这样做,因为包是基于 .BPL 的。 - Marco van de Voort

1

避免使用bpl方法,因为您将不得不随软件一起发送一个大的bpl包,从而使分发变得笨重。

我们为什么要使用Delphi编译小型独立程序,这些程序可以在任何地方运行而不需要任何运行时依赖关系。使用bpls意味着打败了这个目的。

我不知道您对DLL的熟悉程度如何,但我建议您使用DLL。

  • 这将为其他开发人员(可能对您的软件感兴趣)提供机会,使用任何开发语言(只要该语言能够生成dll)编写自己的插件,这些插件可以用于您开发的软件中。
  • 另一件事是,您将免于Delphi的vcl版本依赖关系暴政。这是Delphi至今的一个主要弱点。

我决定使用DLL,因为有计划可能插件会向其他插件公开一些功能 - 因此,如果安装第二个插件,第一个插件可以使用其功能。如果没有安装,则不会失败,但也没有扩展的可能性。无论如何,这意味着需要使用“公共接口包”编译两个软件包,如果不存在,则它将无法正常工作。没有意义。我已经决定在其他环境(非VCL)中无法编写,因为我无法为这样的基类编写包装器,比如TForm等等... - migajek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接