65.9K
CodeProject 正在变化。 阅读更多。
Home

多平台插件开发变得容易!

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.04/5 (25投票s)

2004 年 5 月 9 日

5分钟阅读

viewsIcon

116345

downloadIcon

1885

如何使用和开发多平台插件。

引言

您是否曾想过如何用相同的代码为 Windows 和 Linux 等多个平台开发插件?那么,您应该仔细看看 Simple Plug-in Layer (SPL) 库!

关于此库

SPL (Simple Plug-in Layer) 库是一个用于插件开发的开源 SDK (LGPL 许可证)。使用 SPL,您可以扩展任何用 C/C++ 编写的应用程序来使用您自己的插件,SPL 将为您处理所有管理、加载和卸载工作。此外,整个框架完全支持跨平台,因此您无需为 SPL 提供的平台开发同一插件的多个版本。

该库由 Andreas Loeffler 和 René Stuhr 开发。请访问 此网站 获取更新和更多关于 SPL 的有用信息。

特点

  • 开源,使用 LGPL 许可证。
  • 免费,完全免费,即使商业用途。
  • 平台无关的架构。
  • 提供 Linux 和 Win32 的实现,更多平台即将推出...
  • 完全兼容 Doxygen-/Javadoc- 的文档。
  • 可选宏,用于快速简便的插件开发。
  • 可变插件参数,用于可扩展的 API。
  • 线程安全,适用于复杂应用程序。
  • 使用 STL 库实现稳定且可移植的容器。
  • 面向对象的設計,易於扩展。
  • 可自定义为 32 位或 64 位系统。
  • 完全用 C++ 编写,除了 STL 之外没有其他依赖项。
  • 可以构建为静态/共享库或 DLL (仅限 Win32)。
  • 各种平台上的示例,逐步解释开发过程。
  • 源代码采用统一风格编写。

概述

SPL 分为两部分:供希望使用插件的应用程序使用的函数/类,以及插件开发方面。插件开发方面提供了宏,您可以选择使用它们来加快插件开发速度。

插件由四个简单的 C 函数组成,其中除一个外,都可以使用 SPL 的宏实现为“默认函数”,而无需任何代码。

  • GetInfo
  • 初始化
  • Run (不能用作默认函数)
  • 关机

“默认函数”是什么意思?默认函数是一个没有代码的简单函数。由于 SPL 在任何情况下都需要这四个函数,因此您可以使用 SPL 的宏来实现它们。如果您想以特殊方式使用其中一个函数,只需不使用函数宏,而是自己实现该函数。

对于这三个函数,SPL 使用以下宏

SPL_IMPLEMENT_PLUGIN_GETINFO();
SPL_IMPLEMENT_PLUGIN_INITIALIZE();
SPL_IMPLEMENT_PLUGIN_SHUTDOWN();

那么,为什么 Run 函数没有这样的宏呢?嗯,如果我们有这样的宏,Run 函数将默认实现,没有任何代码,因此插件什么也不做 :-)。

注意:如果您想使用/编译带有 Windows 的插件,您需要 SPL 提供的两个附加宏,它们称为

SPL_DEFINE_PLUGIN_EXPORTS();
SPL_DEFINE_PLUGIN_DLLMAIN();

这两个宏提供了某些特定于 Windows 的代码,而其他平台(如 Linux)则不使用。不用担心,您可以安全地将它们放入插件中,无论您是否要在 Linux 平台上编译/使用插件,这都没有关系,SPL 会在内部为您处理所有事情,因此您无需更改任何内容即可在不同平台上编译使用您的插件!

一个“Hello-World”插件

让我们从一个非常简单的“Hello-World”插件开始。此示例也包含在 SPL 包中。我们的目标是创建一个简单的插件,该插件可以在 Windows 和 Linux 上编译/运行,而无需在“移植”它时更改源代码。好吧,实际上您无需“移植”任何东西 ;-)

看看头文件

#if SPL_PLATFORM == SPL_PLATFORM_WIN32
 #include <windows.h>
#endif
SPL_DEFINE_PLUGIN_EXPORTS();
SPL_DEFINE_PLUGIN_INFO( 1,            ///< The build number.
    1,                                ///< The major version 
                                      ///(e.g. 1.xx). 
    0,                                ///< The minor version 
                                      ///(e.g. 0.10).
    true,                             ///< Does this plugin show its 
                                      ///arguments to the public?
    "plHelloWorld",                   ///< The plugin's name.
    "United Bytes",                   ///< The plugin's vendor.
    "Hello world, our first plugin!", ///< The plugin's general 
                                      ///description.
    "Simple test plugin! :-)",        ///< The plugin's additional 
                                      ///description.
    "http://www.unitedbytes.de",      ///< The plugin vendor's homepage.
    "info@unitedbytes.de",            ///< The plugin vendor's 
                                      ///email address.
    "ConsoleExampleAPI" );            ///< The plugin's UUID.

这确实是您的头文件所需的所有内容。我们已经讨论了 SPL_DEFINE_PLUGIN_EXPORTS(); 宏,所以让我们来看看宏

SPL_DEFINE_PLUGIN_INFO();

这个宏从 slcPluginInfo 派生一个类,该类负责保存插件信息,如名称、版本、构建号、供应商等,并创建一个名为 g_pluginInfo 的全局实例。所有 SPL 的默认函数宏都需要此全局对象。

硬核程序员须知:您不需要 SPL 的任何宏来实现工作,SPL 包中包含了一个简单的示例,说明如何不使用宏来实现插件。

既然我们的头文件现在完成了,让我们进入我们的 .cpp 文件

#include "plHelloWorld.h"
SPL_DEFINE_PLUGIN_DLLMAIN();
SPL_IMPLEMENT_PLUGIN_GETINFO();
SPL_PLUGIN_API bool SPL_INIT_NAME_CODE( 
                   slcPluginArgs* a_pPluginArgs )
{
 printf( "HelloWorld: Hi there! Here " + 
         "we could initialize something!\n" );
 return true;
}
SPL_PLUGIN_API bool SPL_RUN_NAME_CODE( 
                   slcPluginArgs* a_pPluginArgs )
{
 printf( "HelloWorld: Hi, this is the plugin's " + 
                                "run function!\n" );
 return true;
}
SPL_PLUGIN_API bool SPL_SHUTDOWN_NAME_CODE( 
                          slcPluginArgs* a_pPluginArgs )
{
 printf( "HelloWorld: Bye, bye world, this " + 
                    "is the shutdown function.\n" );
 return true;
}

看起来很简单,不是吗?我在这里没有使用任何“默认函数”宏(GetInfo 函数除外),因为我想展示如何自己使用所有函数(再次,GetInfo 除外)。

“嗯,听起来不错,但这些函数什么时候被调用?”我听到你低语……这是一个好问题!

几乎没有人会自己实现 GetInfo 的原因在于,此函数基本上所做的只是返回一个指向插件信息结构的指针,该结构是我们通过使用宏 SPL_DEFINE_PLUGIN_INFO() 在头文件中填写的。

Initialize 函数在插件成功加载时被调用,用户代码手动调用 GetInfo 以获取有关插件的更多信息,Run 包含实际的插件代码,Shutdown 要么在用户程序结束时由用户手动调用,要么由 SPL 的析构函数调用,以便所有插件都有机会清理自己。

SDK 中包含了各种使用 SPL 的示例,还包含了一个 Doxygen 生成的所有参数和函数的文档。还包括 Microsoft .NET 2003、Microsoft Visual Studio 6.0 和 Linux (GCC) 的构建。

MFC 示例应用程序的截图

此截图显示了 SDK 中包含的一个示例应用程序

左侧:我们的 MFC 示例应用程序显示所有已加载的插件,并使用 SPL 库作为 DLL 构建。在左侧的列表视图中,您可以看到所有已加载的插件,并选中了第一个插件。在右侧的小窗口中,您可以看到所选插件的信息。您可以使用选定的插件修改给定的文本。

右侧:红线标记了示例应用程序本身。在该线下方,您可以看到所有已加载的插件进程。

资源

请访问 此处 以获取有关此库的更多信息。

© . All rights reserved.