【问题标题】:How best to add Plugin Capability to a Delphi program如何最好地将插件功能添加到 Delphi 程序
【发布时间】:2008-12-14 00:02:26
【问题描述】:

我希望为我在 Delphi 开发的程序中添加让用户编写插件的功能。该程序是一个没有使用 DLL 的单一可执行文件。

这将允许用户社区为我的程序编写扩展,以访问内部数据并添加他们可能认为有用的功能。

我在Suggestions for Adding Plugin Capability? 看到过帖子,但它的答案似乎无法转移到 Delphi 程序。

如果可能,我希望添加此功能并将我的应用程序保留为单个可执行文件,而不需要任何 DLL 或其他模块。

您是否知道任何可以建议如何在 Delphi 中最好地做到这一点的资源、组件或文章,或者您有自己的建议?

【问题讨论】:

  • 在我的回答中查看更多解释

标签: delphi plugins


【解决方案1】:

添加插件功能最通用的方法是使用 COM。 Eric Harmon 的《Delphi Com Programming》是一本让您开始上路的好书。虽然它最初是为 Delphi 版本 3 到 5 编写的,但书籍内容仍然适用于最新版本的 Delphi。

就我个人而言,我已将这种技术与活动脚本一起使用来允许最终用户进行自定义。

【讨论】:

    【解决方案2】:

    我正在使用插件来实现我正在构建的游戏引擎中的大部分功能。主 EXE 由脚本引擎、插件管理器、一些基本的图形例程和其他部分组成。我正在使用 JEDI VCL 库中的 TJvPluginManager。这是一个非常好的管理器,它可以将您想要的任何内容添加到您的程序中。查看软件包中包含的演示,了解它是如何工作的。唯一的缺点是它会在您的程序中添加大量 JCL/JVCL 代码,但如果您已经在使用其他 JVCL 组件,这并不是真正的问题。

    【讨论】:

    • TJvPluginManager 是否将插件限制为 Delphi 编写的插件?无论如何,接口是如何通过 COM 实现的?
    • 是的,插件必须用 Delphi 编写。 (或者可能是 C++ Builder。不确定。)插件必须来自 TJvPlugin 基类,它基本上只是插件功能的包装器,以便与管理器对话。您可以将其实现为 DLL 或 BPL。
    【解决方案3】:

    起初我选择了 BPL 和 DLL 基础插件。并且发现它们难以维护。

    如果你使用BPL系统,那么你需要匹配BPL版本和EXE版本。这包括可以破坏某些东西的 Delphi 更新。我发现(很难)如果我需要在每个版本中包含我所有的插件,那么拥有插件是没有意义的。

    然后我切换到普通的 DLL 插件。但是那个系统只是复杂的代码库。这不是一件好事。

    在浏览网络时,我发现了 Lua 嵌入式脚本语言,并随它一起交付。 Lua 是 150K 的 DLL,内嵌字节码编译器、解释器和非常简单智能的动态编程语言。

    我的插件是简单的 lua 脚本。易于维护和制造。有预制的 Delphi 示例,因此您可以将任何类或过程导出为 Lua 表或函数。 GUI 与否。例如,我的应用程序中有 TurboPower Abbrevia 用于压缩。我将我的 zipping 类导出到 lua,现在所有插件都可以调用 zip('.', 'dir.zip') 和 unzip()。然后我切换到 7zip,只实现了旧类来使用 7zip。所有插件都可以正常工作,并支持 new zip('.', 'dir.7z')。

    我制作了 TLuaAction,它从其脚本中调用 Execute()、Update()、Hint() 过程。

    Lua 也有它自己的插件系统,可以很容易地为其添加功能。例如 luacom make 易于使用 COM 自动化,luainterface 允许从 lua 调用 .net。 有关更多信息,请参阅luaforge。有 Delphi 制作的 Lua IDE,有源代码。

    【讨论】:

      【解决方案4】:

      实际上,the accepted answer to the question you cite 也非常适合 Delphi。您的插件将是 DLL,您可以指定它们应导出具有特定名称和签名的函数。然后,您的程序将加载 DLL(使用LoadLibrary)并获取函数的地址(使用GetProcAddress)。如果 DLL 没有加载,或者函数不存在,则 DLL 不是您的应用程序的插件。

      获得 DLL 的地址后,就可以调用它了。您可以将函数传递给表示您希望公开的应用程序部分的接口。您还可以要求该函数返回一个接口,其中包含您的应用程序将在不同时间调用的方法。

      在测试您的插件系统时,最好自己用 Delphi 以外的语言编写插件。这样一来,您就可以更加确信自己没有无意中要求每个人都使用 Delphi。

      【讨论】:

      • +1 提示插件应该也可以用 Delphi 以外的其他语言编写。否则,将 RemObjects Pascal 脚本包含到您的应用程序中并完成它要简单得多。在这两种情况下都需要为您的内部对象创建一个接口,...
      • 并且使用内部脚本,您不必为插件界面本身投入更多工作。此外,请确保无需关闭您的应用程序即可测试、添加和删除插件。
      • "你可以将函数传递给..." 你认为其他语言可以在没有 COM 的情况下使用或实现 delphi 接口吗?
      • Mghie:PascalScript 很棒,但它不能替代真正的插件系统,因为它只实现了大约 2/3 的语言功能集,而且每当有人问 Carlo Kok 剩下的功能时,他几乎总是说他没有实施它们的计划。
      • Ahmet,Delphi 接口 COM 接口。不过,该语言不需要特别特别的支持。普通的旧 C 可以做到这一点。
      【解决方案5】:

      我要问的第一个问题是,您需要插件来访问主机应用程序的 UI,还是添加它们自己的 UI 元素?或者插件是否仅限于查询和/或向您的主机应用提供数据?

      后者更容易,并开辟了两种可能性。其他人已经提到了 DLL,这是第一种方法。某些警告适用 - 通常,您应该仅使用 Windows API 中使用的数据类型与 dll 进行交互。这样,您可以确保插件 DLL 将理解您的数据类型,无论它们是用什么语言/编译器创建的。(例如,使用 PChars,而不是字符串。通常不要将 Delphi 类(如 TStream)传递给一个 DLL。这在某些情况下似乎可以工作,但通常是不安全的,因为即使 DLL 是在 Delphi 中编译的,它也可能是编译器的不同版本,对 TStream 的概念略有不同)。 Google 在 Delphi 中使用 DLL,您会发现更多提示。

      另一种尚未提及的方法是在您的应用程序本身中启用脚本。有几个非常强大的第 3 方脚本引擎,包括商业的和免费的,其中大多数允许您与脚本交换 Delphi 对象。其中一些库仅支持 Pascal 作为脚本语言,其他库将允许您使用 Basic(对于初学者用户可能更好)或其他语言。例如,请参阅http://www.remobjects.com/free.aspx 上的 RemObjects Pascal 脚本(免费)。

      目前我最喜欢的脚本解决方案是来自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 肯定是。

      Google 也提供“Delphi 插件框架”。有一些现成的解决方案,但据我所知,它们通常使用 BPL,但用处有限。

      【讨论】:

      • +1。这里有很多非常好的建议。做一个插件界面后果很多,时间很长,所以提前想的越多越好。
      【解决方案6】:

      我前段时间尝试创建overview of all such options。我们与我的读者/评论者一起建立了这份名单:

      • 从程序加载的 DLL/BPL。
      • 从沙箱加载的 DLL/BPL(可能是程序的另一个副本或专门的“服务器”应用程序,它通过消息/套接字/msmq/命名管道/邮件槽/内存映射文件与主程序通信)。
      • COM(在其任何变体中)。
      • DDE(请不要)。
      • 通过标准输入/输出进行通信的外部程序。
      • 通过文件进行通信的外部程序(文件名是程序的参数)。
      • 通过放置文件夹工作的外部程序(对批处理很有用)。
      • 与 windows 消息/windows 套接字/msmq/命名管道/邮件槽/内存映射文件/数据库发布-订阅通信的外部程序。

      【讨论】:

        【解决方案7】:

        如果要在 Delphi 或 C++ builder 中开发插件,请使用包 + 接口。 Delphi OTA 就是一个很好的例子。 如果插件将独立于语言,COM 是一个不错的选择。

        补充:如果您不使用 COM,您可能需要为每种语言提供 SDK。并且不同语言之间的数据类型处理可能很痛苦(例如delphi字符串类型)。 Delphi COM 支持非常好,你不需要担心一些细节。这些大多隐含在 Delphi COM 支持中。不要试图再次发明轮子。我很惊讶为什么人们不倾向于提及它。

        【讨论】:

        • 我不熟悉 Delphi OTA 是什么,并且最初的 Google 搜索没有帮助。您是否有指向描述它的资源的良好链接?
        • Delphi OTA:开放工具 API。谷歌第一次点击:delphi.about.com/od/objectpascalide/a/wizardsexperts.htm
        • OTA = 打开工具 api。它提供了一堆接口来使用专家或设计时间包中的 IDE 功能。例如 GExpert 使用了很多 OTA 功能。 OTA 不是 delphi 程序员的通用插件系统。对delphi IDE来说是特别的。我认为这对你来说是一个很好的例子。
        • 不幸的 URL:wizard-sex-perts.htm
        【解决方案8】:

        我找到了 Tim Sullivan 的一篇文章:
        Implementing Plug-Ins for Your Delphi Applications

        【讨论】:

          【解决方案9】:

          你可以看看 Remobjects 的Hydra。这不仅可以让您添加插件,还可以混合使用 win32 和 .net。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-12-01
            • 2020-09-24
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多