【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 运行结果

在这里插入图片描述

  • 23
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
引用中的代码是一个使用Qt的QLibrary的示例,用于加载和使用一个名为"Add"的动态链接库。首先,通过调用QLibraryload()函数加载库文件。如果加载失败,会输出错误信息。然后,通过resolve()函数获取动态链接库中的函数指针,并将其转换为一个特定的函数型。如果函数指针不为空,就可以调用该函数,并输出结果。如果函数指针为空,则输出错误信息。最后,调用a.exec()函数启动Qt的事件循环。 引用是关于QLibraryresolve()函数的静态成员函数的文档说明。这个函数用于在给定库文件中解析指定的符号,并返回一个QFunctionPointer对象。 引用中的代码也是一个使用QLibrary的示例,不同的是这里使用了reinterpret_cast将函数指针转换为特定的型Fun。然后,通过调用lib.resolve()函数获取动态链接库中名为"sum"的函数的指针。如果指针不为空,就可以调用该函数,并输出结果。如果指针为空,则输出错误信息。 综上所述,QLibraryQt中的一个,用于加载和使用动态链接库。通过调用load()函数加载库文件,resolve()函数获取函数指针,然后可以使用这些函数指针来调用库中的函数。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [QT 使用QLibrary加载动态库](https://blog.csdn.net/qq_32348883/article/details/126526701)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *2* *3* [Qt插件:QLibrary](https://blog.csdn.net/kenfan1647/article/details/120178016)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值