列表1是一个指定了通用插件接口的头文件。没有深入细节并解释所有事情之前,让我们看看它提供了什么。
#ifndef PF_PLUGIN_H
#define PF_PLUGIN_H
#include
#ifdef __cplusplus
extern "C" {
#endif
typedef enum PF_ProgrammingLanguage
{
PF_ProgrammingLanguage_C,
PF_ProgrammingLanguage_CPP
} PF_ProgrammingLanguage;
struct PF_PlatformServices_;
typedef struct PF_ObjectParams
{
const apr_byte_t * objectType;
const struct PF_PlatformServices_ * platformServices;
} PF_ObjectParams;
typedef struct PF_PluginAPI_Version
{
apr_int32_t major;
apr_int32_t minor;
} PF_PluginAPI_Version;
typedef void * (*PF_CreateFunc)(PF_ObjectParams *);
typedef apr_int32_t (*PF_DestroyFunc)(void *);
typedef struct PF_RegisterParams
{
PF_PluginAPI_Version version;
PF_CreateFunc createFunc;
PF_DestroyFunc destroyFunc;
PF_ProgrammingLanguage programmingLanguage;
} PF_RegisterParams;
typedef apr_int32_t (*PF_RegisterFunc)(const apr_byte_t * nodeType, const PF_RegisterParams * params);
typedef apr_int32_t (*PF_InvokeServiceFunc)(const apr_byte_t * serviceName, void * serviceParams);
typedef struct PF_PlatformServices
{
PF_PluginAPI_Version version;
PF_RegisterFunc registerObject;
PF_InvokeServiceFunc invokeService;
} PF_PlatformServices;
typedef apr_int32_t (*PF_ExitFunc)();
typedef PF_ExitFunc (*PF_InitFunc)(const PF_PlatformServices *);
#ifndef PLUGIN_API
#ifdef WIN32
#define PLUGIN_API __declspec(dllimport)
#else
#define PLUGIN_API
#endif
#endif
extern
#ifdef __cplusplus
"C"
#endif
PLUGIN_API PF_ExitFunc PF_initPlugin(const PF_PlatformServices * params);
#ifdef __cplusplus
}
#endif
#endif /* PF_PLUGIN_H */
列表1
首先你应当注意到这是一个C文件。这允许插件框架可以由纯C系统编译使用并可用来写纯C插件。但是,它不仅仅局限在C上,且实际上大多数情况下用在C++中。
枚举类型PF_ProgrammingLanguage允许插件声明到用C++实现的插件管理器中。
PF_ObjectParams是一个抽象的结构体,创建插件时用于传递参数给插件对象。
PF_PluginAPI_Version被用于商讨版本问题,并保证插件管理器只加载合适版本的插件。
函数指针PF_CreateFunc和PF_DestroyFunc(由插件来实现)允许插件管理器来创建和销毁插件对象(每个插件注册这样的函数到插件管理器中。)
PF_RegisterParams结构体包含初始化时插件必须提供给插件管理器的所有信息。(版本信息,创建/销毁函数,编程语言)
PF_RegisterFunc(由插件管理器实现)允许每个插件为每种它所支持的对象类型注册一个PF_RegisterParams结构体。注意这个方案允许一个插件注册一个对象的不同版本和多个对象类型。
PF_InvokeService函数指针是一个通用的函数,查检可以用其来调用主系统提供的服务如日志、事件通知及错误报告。其签名(signature)包括服务名称和指向一个参数结构体不透明的指针。插件应当知道可用的服务以及如何调用它们(或者,如果你希望使用PF_InvokeService,你可以自己实现服务。)
PF_PlatformServices结构体聚集了我刚刚提到所有的由平台提供给插件的服务(版本,注册对象,执行服务函数)。该结构体在初始化时传递给每个插件。
PF_ExitFunc定义了插件退出函数,由插件来实现。
PF_InitFunc定义了插件初始化函数指针。
PF_initPlugin是动态插件(由动态链接库/共享库来部署的插件)实际的初始化函数的签名(signature)。从动态插件中导出它的名字,因此插件管理器可以在加载插件时调用它。它接受一个指向PF_PlatformServices结构体的指针,因此所有的服务在初始化时立刻可用(这是注册对象的正确时机)并返回一个指向退出函数的指针。
注意静态插件(实现在静态库中且直接连接到主执行体中)应当实现一个有C linkage的init函数,但禁止将其命名为PF_initPlugin。原因是如果有多个静态插件,他们都将有一个同样的初始化函数名字,你的编译器痛恨这个。
静态插件的初始化有所不同。他们必须显式地由主执行体初始化。主执行体将通过PF_InitFunc的签名调用它们的初始化函数。很不幸,这意味着每当一个新的静态插件加入/移出系统时,主执行体需要被修改,并且各种各样的init函数的名字必须是对等的(coordinated)。
有一种试图解决该问题的技术叫做“自动注册”。自动注册通过静态库中一个全局的对象来达到目的。该对象