【Qt】动态加载DLL之QLibrary类学习(内含完整Demo源码)

在这里插入图片描述

前言

本文代码测试环境:

编程语言构建套件IDE操作系统
C++ 11Desktop Qt 5.9.9 MSVC2013 64bitQt Creator 4.11.0Windows10

一、QLibrary简介

QLibrary 类用于在运行时加载共享库。一个 QLibrary 对象实例操作一个单独的共享对象文件(也称为“”或“DLL”)。

QLibrary 提供了一种平台独立的方式来访问库中的功能。你可以在构造函数中传递文件名,也可以通过 setFileName()显式设置文件名。

在加载库时,如果指定的不是绝对路径,QLibrary 会在系统默认的库路径中进行搜索(例如,Unix 系统上的 LD_LIBRARY_PATH);反之如果在构造时指定了库的绝对路径,则会优先尝试该路径。

二、常用方法

2.1 构造函数

原型:

QLibrary(const QString &fileName, QObject *parent = Q_NULLPTR)

QObject *parent是可选参数,即可省略。

解释:
构造一个具有指定父对象的库对象,该对象将加载由fileName指定的库。Qt官方建议在fileName中省略文件的扩展名,因为Qlibrary会自动根据平台寻找带有适当后缀的文件,例如在Unix上为".so",在macOSiOS上为“.dylib”,在Windows上为“.dll”。

2.2 设置要访问的动态库——setFileName()

原型:

void setFileName(const QString &fileName)

解释:
fileName:要加载的共享库的文件名。它是一个QString类型的参数,可以是一个相对路径或绝对路径(个人建议使用绝对路径)。

2.3 加载动态库——load()

原型:

bool load()

解释:

load()方法用于加载由QLibrary对象当前设置的文件名指定的动态库。如果加载成功,该方法返回true,否则返回false

2.4 获取动态库的名字——fileName()

原型:


QString fileName() const

解释:

fileName()方法用于获取Qlibrary对象当前所设置的动态库文件名。
这个文件名是在构造QLibrary对象时通过构造函数设置的,或者之后通过setFileName()方法设置的。

使用场景:
fileName() 方法通常用于调试或日志记录,以确认 QLibrary 对象当前所引用的库文件名是否正确。它也可以用于在动态加载库之前或之后检查文件名,以确保加载的是预期的文件。

2.5 解析共享库中的符号——resolve()

原型:

QFunctionPointer resolve(const char *symbol);

解释:

resolve()方法用于解析动态库中指定的符号,并返回一个指向该符号的函数指针。符号通常指的是库中的函数全局变量名称

参数:
symbol:要解析的符号的名称,以C字符串 (const char *) 的形式提供。
如果符号无法解析或库无法加载,则函数返回0。

注意事项:

  1. 该方法有隐式加载的行为。即:如果动态库尚未被加载,调用resolve()方会隐式地尝试加载动态库。这是通过调用load()方法实现的,调用者不需要关心或处理这个加载过程的细节,QLibrary会在内部处理这些细节。
  2. 解析的符号必须作为 C 函数从库中导出,这意味着如果使用C++编译器编译库,函数需要被封装在 extern C 块中。
  3. Windows平台上,还需要使用 __declspec(dllexport) 宏来显示导出函数。

根据注意事项第2、第3条,给出以下示例代码 ↓ ↓ ↓:

  extern "C" 
  {
	  __declspec(dllexport) int avg(int a, int b)
	  {
	      return (a + b) / 2;
	  }
  }

三、示例(Demo)

看完以上内容,写个Demo练习巩固下。

Demo具体内容分为动态库部分和主程序部分:

  1. 动态库:实现一个加法运算,将传递进来的数值相加,并将结果传回;
  2. 主程序:使用QLibrary类加载、使用动态库。

这里粘贴部分主要源码(如.pro文件等,不在这里体现),整个项目见链接:可供学习Qt中QLibrary类的一个Demo,免费下载

3.1 动态库DLL源码

AdditionFunc.h

#ifndef ADDITIONFUNC_H
#define ADDITIONFUNC_H

#if _MSC_VER >= 1600 //VS2015>VS>VS2010, MSVC VER= 10.0 -14.0
#pragma execution_character_set("utf-8")
#endif

#include <QObject>

typedef struct
{
    int a;
    int b;

    int sum;
}T_CoreData;

class AdditionFunc : public QObject
{
    Q_OBJECT
public:
    explicit AdditionFunc(T_CoreData& tCoreData, QObject *parent = nullptr);

    int IntegerAddition(int a, int b);
signals:

};

#endif // ADDITIONFUNC_H

AdditionFunc.cpp

#include <QDebug>

#include "AdditionFunc.h"

AdditionFunc::AdditionFunc(T_CoreData& tCoreData, QObject *parent) : QObject(parent)
{
    tCoreData.sum = IntegerAddition(tCoreData.a, tCoreData.b);
    qDebug() << "我是一个加法运算插件," << "Result = " << tCoreData.sum;
}

int AdditionFunc::IntegerAddition(int a, int b)
{
    return (a+b);
}

PluginInterface.cpp 这个是插件接口文件,主程序加载多个插件时可以使用同一接口文件,简化编程

#include <QDebug>
#include "AdditionFunc.h"

template <class TemPluginClass>
class InitPlugin
{
public:
    InitPlugin()
    {

    }
    ~InitPlugin()
    {
        delete TemPluginClass();
    }

    TemPluginClass* Create(T_CoreData& tCoreData)
    {
        return new TemPluginClass(tCoreData);
    }
};

extern "C"
{
    __declspec(dllexport) QObject* InterfaceFunc(T_CoreData& tCoreData)
    {
        InitPlugin<AdditionFunc> *pCInitPlugin = new InitPlugin<AdditionFunc>;
        qDebug() << "InterfaceFunc() run..." ;
        return pCInitPlugin->Create(tCoreData);
    }
}

3.2 主程序部分

MyMainWindow.h

#ifndef MYMAINWINDOW_H
#define MYMAINWINDOW_H

#include <QMainWindow>
#include <QLibrary>

#if _MSC_VER >= 1600 //VS2015>VS>VS2010, MSVC VER= 10.0 -14.0
#pragma execution_character_set("utf-8")
#endif

QT_BEGIN_NAMESPACE
namespace Ui { class MyMainWindow; }
QT_END_NAMESPACE

typedef struct
{
    int a;
    int b;

    int sum;
}T_CoreData;

class MyMainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MyMainWindow(QWidget *parent = nullptr);
    ~MyMainWindow();

    int runUser();

public:
    QLibrary *m_CQLibrary;

private:
    Ui::MyMainWindow *ui;

    T_CoreData m_tCoreData;
};
#endif // MYMAINWINDOW_H

MyMainWindow.cpp

#include <QDebug>

#include "MyMainWindow.h"
#include "ui_MyMainWindow.h"

typedef QObject* (*PluginInterface)(T_CoreData& tCoreData);

MyMainWindow::MyMainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MyMainWindow)
{
    ui->setupUi(this);
    m_tCoreData.a = 6;
    m_tCoreData.b = 7;
    runUser();
}

MyMainWindow::~MyMainWindow()
{
    delete ui;
    delete m_CQLibrary;
}

int MyMainWindow::runUser()
{
    PluginInterface pPluginInterface;       // 声明接口函数指针

    QString QStrPluginsPath = QCoreApplication::applicationDirPath() + "/../Plugins";
    QStrPluginsPath += "/PluginAddition";

    m_CQLibrary = new QLibrary(QStrPluginsPath);

    if (m_CQLibrary->load())  // 加载成功
    {
        pPluginInterface = (PluginInterface)m_CQLibrary->resolve("InterfaceFunc");
        if (nullptr != pPluginInterface)
        {
            qDebug() << "插件创建成功,插件名字是:" << m_CQLibrary->fileName();
            pPluginInterface(m_tCoreData);
            qDebug() << "主程序打印计算结果:" << m_tCoreData.sum;
        }
    }
    else        // 加载失败
    {
        qDebug() << "插件加载失败!"<< m_CQLibrary->load();
    }

    return 0;
}

main.cpp

#include "MyMainWindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MyMainWindow w;
    w.show();
    return a.exec();
}

3.3 运行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值