最近在用QPluginLoader为server程序做一个打补丁的功能,即让server程序定时检索是否有最新的补丁包,若有则下载并替换原先的功能,从而使server程序在不退出的情况下实现不间断升级。
QPluginLoader的使用方法如下。
接口定义
接口类必须是虚基类,除构造函数、析构函数(最好定义为虚函数)外的成员函数都必须是纯虚函数。
// 定义接口
class SGISSvrPluginInterFace
{
public:
virtual ~SGISSvrPluginInterFace(){};
// 获取插件信息
virtual bool getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo) = 0;
};
QT_BEGIN_NAMESPACE
// Q_DECLARE_INTERFACE(接口类名, 接口标识符)
// 声明接口,Q_DECLARE_INTERFACE 宏告诉Qt 这个纯虚类是一个插件接口类
Q_DECLARE_INTERFACE(SGISSvrPluginInterFace, "THP.SGISSvrPluginInterFace/2.1.20.1");
QT_END_NAMESPACE
插件基类定义
定义一个所有插件的基类,server程序的每一个接口功能单独作为一个插件(派生类)。这样:
一方面,具体的插件可只在需发布补丁时实现;
另一方面,每次可单独发布某个插件(最小化发布,插件小),同时可告诉server程序哪些接口有可用插件。这样在调用某接口时,若发现有可用插件,则使用插件中的新功能,否则继续原功能。
插件必须继承接口类SGISSvrPluginInterFace和QObject。
// 定义所有插件的基类
// 必须继承QObject
class SGISSvrPluginBase : public QObject, public SGISSvrPluginInterFace
{
Q_OBJECT
// Q_INTERFACES 宏,告诉Qt MOC 接口 SGISSvrPluginInterFace 的存在
// Qt MOC 在为 Q_INTERFACES 宏生成代码时,需用到 接口标识符
// 将该接口注册到Qt的meta-object system
Q_INTERFACES(SGISSvrPluginInterFace)
public:
SGISSvrPluginBase();
virtual ~SGISSvrPluginBase();
// 获取插件信息
virtual bool getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo);
virtual bool func1();
virtual bool func2();
}
// 获取插件信息
bool SGISSvrPluginBase::getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo)
{
pTSvrServicePluginInfo->m_strPluginName = GB("SGISSvrPluginBase");
pTSvrServicePluginInfo->m_nSeqID = 0;
pTSvrServicePluginInfo->m_strPluginVersion = GB("0.0.0.0");
return true;
}
bool SGISSvrPluginBase::func1()
{
return false;
}
bool SGISSvrPluginBase::func2()
{
return false;
}
插件定义
在插件cpp文件的末尾,必须使用宏Q_EXPORT_PLUGIN2()来指定使用哪一个类提供插件。
class class_1 : public SGISSvrPluginBase
{
Q_OBJECT;
public:
GISSvr_GetConnection();
~GISSvr_GetConnection();
// 获取插件信息
virtual bool getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo);
virtual bool func1();
};
// 获取插件信息
bool class_1::getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo)
{
if (!pTSvrServicePluginInfo.isNull())
{
pTSvrServicePluginInfo->m_strPluginName = GB("GetConnection");
pTSvrServicePluginInfo->m_strPluginVersion = GB("1.6.1.0");
}
return true;
}
bool class_1::func1()
{
/*
......
*/
return true;
}
// Q_EXPORT_PLUGIN2(插件名, 类名)
Q_EXPORT_PLUGIN2("class_1", class_1)
class class_2 : public SGISSvrPluginBase
{
Q_OBJECT;
public:
GISSvr_GetConnection();
~GISSvr_GetConnection();
// 获取插件接口信息
virtual bool getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo);
virtual bool func2();
};
// 获取插件接口信息
bool class_2::getPluginInterFaceInfo(QSharedPointer<SGISSvrPluginInfo> &pTSvrServicePluginInfo)
{
if (!pTSvrServicePluginInfo.isNull())
{
pTSvrServicePluginInfo->m_strPluginName = GB("GetConnection");
pTSvrServicePluginInfo->m_strPluginVersion = GB("1.6.1.0");
}
return true;
}
bool class_2::func2()
{
/*
......
*/
return true;
}
// Q_EXPORT_PLUGIN2(插件名, 类名)
Q_EXPORT_PLUGIN2("class_2", class_2)
工程属性配置
为SGISSvrPluginBase及class_1、class_2等各插件类的头文件配置工程属性。这样,头文件经编译后会生成各自的moc_***.cpp文件,该文件需在工程中#include引用。
插件的加载与卸载
QPluginLoader pPluginLoader("../Debug/PluginDll.dll");
SGISSvrPluginBase *pGISSvrPlugin;
if (pPluginLoader->load())
{
// 直接从插中获取插件的实例
pGISSvrPlugin = dynamic_cast<SGISSvrPluginBase *>(pNewGISSvrPluginInfo->m_pPluginLoader->instance());
}
// 若多个实例使用了相同的插件,则唯有当所有实例都调用 unload()时,函数才会返回true,插件才会被卸载,之前的实例在调用unload()时都会返回false。
pGISSvrPlugin.unload();