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






4.04/5 (25投票s)
2004 年 5 月 9 日
5分钟阅读

116345

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 构建。在左侧的列表视图中,您可以看到所有已加载的插件,并选中了第一个插件。在右侧的小窗口中,您可以看到所选插件的信息。您可以使用选定的插件修改给定的文本。
右侧:红线标记了示例应用程序本身。在该线下方,您可以看到所有已加载的插件进程。
资源
请访问 此处 以获取有关此库的更多信息。