QPluginLoader 加载/卸载插件

最近在用QPluginLoader为server程序做一个打补丁的功能,即让server程序定时检索是否有最新的补丁包,若有则下载并替换原先的功能,从而使server程序在不退出的情况下实现不间断升级。
QPluginLoader的使用方法如下。

接口定义

接口类必须是虚基类,除构造函数、析构函数(最好定义为虚函数)外的成员函数都必须是纯虚函数。

// 定义接口
class SGISSvrPluginInterFace
{
public:

    virtual ~SGISSvrPluginInterFace(){};

    // 获取插件信息
    virtual bool getPluginInterFaceInfo(QSharedPointer &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 &pTSvrServicePluginInfo);

    virtual bool func1();

    virtual bool func2();
}

// 获取插件信息
bool SGISSvrPluginBase::getPluginInterFaceInfo(QSharedPointer &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 &pTSvrServicePluginInfo);

    virtual bool func1();
};

// 获取插件信息
bool class_1::getPluginInterFaceInfo(QSharedPointer &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 &pTSvrServicePluginInfo);

    virtual bool func2();
};

// 获取插件接口信息
bool class_2::getPluginInterFaceInfo(QSharedPointer &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 加载/卸载插件_第1张图片

QPluginLoader 加载/卸载插件_第2张图片

插件的加载与卸载

QPluginLoader pPluginLoader("../Debug/PluginDll.dll");
SGISSvrPluginBase *pGISSvrPlugin;
if (pPluginLoader->load())
{
    // 直接从插中获取插件的实例
    pGISSvrPlugin = dynamic_cast(pNewGISSvrPluginInfo->m_pPluginLoader->instance());
}

QPluginLoader 加载/卸载插件_第3张图片

// 若多个实例使用了相同的插件,则唯有当所有实例都调用 unload()时,函数才会返回true,插件才会被卸载,之前的实例在调用unload()时都会返回false。

pGISSvrPlugin.unload();

你可能感兴趣的:(服务器)