QT 通过动态加载DLL实现插件化

简介

我们可以像JAVA一样规定一个接口,该接口为一个类,类内部全是虚方法,而该类的实现类及具体方法由DLL文件实现。这样,我们就可以动态更换或添加新的功能了。
QT 中提供了显式加载DLL文件的方法,所以不要用 <Windows.h> 文件中加载DLL的方式,这样会影响移植性。

DLL项目的写法

在这里插入图片描述

  • 新建项目后,把 xxx_global.h文件中的内容拷贝到 另一个.h文件开头
    • 拷贝后把 xxx_global.h 文件删除掉
      .h文件的写法示例(dlllib.h)
#ifndef DLLLIB_H
#define DLLLIB_H
// 这下面6行代码是从 xxx_global.h 文件里拷贝过来的。
#include <QtCore/qglobal.h>
#if defined(DLLLIB_LIBRARY)
#  define DLLLIB_EXPORT Q_DECL_EXPORT
#else
#  define DLLLIB_EXPORT Q_DECL_IMPORT
#endif
// 这是对外暴露的类对象
class DLLLIB_EXPORT DllLib
{
public:
    virtual int Add()=0;
};
// 需要提供一个创建该类的方法
// 由于显示调用必须通过函数名找到该方法,所以必须加 extern "C" 前缀,否则函数名会被改写,导致找不到该方法。
extern "C" DLLLIB_EXPORT DllLib* getDllLib(int a,int b);
// 其他方法
extern "C" DLLLIB_EXPORT int getDllLibResult(DllLib* dllLib);

#endif // DLLLIB_H

dlllib.cpp文件

#include "dlllib.h" // 这个是上面那个.h文件
// 我们需要在该文件里具体实现.h文件的接口,你也可以单独把子类抽成.h文件
class MyDllLib:public DllLib{
public:
    MyDllLib(int a,int b):a(a),b(b){}
    int Add(){
        return this->a + this->b;
    }
 private:
    int a;
    int b;
};

// 这个方法很重要,由于是显式加载DLL文件,所以你无法通过new 类名来创建对象,所以DLL文件必须提供创建对象的方法。
DllLib* getDllLib(int a,int b){
    return new MyDllLib(a,b);
}
// 其他方法
int getDllLibResult(DllLib* dllLib){
    return dllLib->Add();
}

写好后点击编译,注意x86和x64是有区别的,选择对应的版本编译(具体是那个版本得看你主程序是哪个版本)
编译好后在输出文件夹里能找到 .lib,.dll 文件,如果是显式加载的话,只需要.dll文件。

QT程序使用

需要的文件:上面得到的dlllib.dll 和 dlllib.h 文件,先将 dlllib.h文件拷贝到主项目的 lib 文件夹(自己建立的)下。
再在项目的Headers上点击右键添加现有文件,把dlllib.h文件添加到项目中。然后先编译一次主项目,生成输出目录后,把 dlllib.dll 文件放到输出文件夹下(和.exe文件同级),因为接下来读取dll文件是直接从.exe同级目录下读取的。
接下来正式开始写主项目:
先在.h 文件里面

#include "lib/dlllib.h"
// 动态加载DLL的时候需要用到该库
#include <QLibrary>

显式加载:

QLibrary lib("DllLib.dll");// 加载DLL文件
if(lib.load()){
    typedef DllLib* (*f_getDllLib)(int, int); // 定义函数指针类型
    typedef int (*f_getDllLibResult)(DllLib*); // 定义函数指针类型

    f_getDllLibResult pAdd2 = reinterpret_cast<f_getDllLibResult>(lib.resolve("getDllLibResult"));  // 获取函数指针,获取对应的方法
    f_getDllLib pAdd = reinterpret_cast<f_getDllLib>(lib.resolve("getDllLib"));  // 获取函数指针,获取对应的方法

    if(pAdd && pAdd2){
        // 都加载成功
        DllLib* dllLib = pAdd(25,30);
        qDebug() << dllLib->Add();
        int ret = pAdd2(dllLib);
        qDebug() << QStringLiteral("方法结果为:") << ret;
    }else{
        qDebug() << "Failed to load function." << endl;
    }

    // 卸载插件
    lib.unload();
}

后记

通过这种方式加载后,那么我们可以给项目规定一个插件接口,再后续编写插件的时候都要遵循这个插件接口的规则,然后我们就可以在不重新编译项目的情况下,对项目进行动态变更或者添加额外的功能。

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值