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

news2024/11/13 20:45:05

各位看官这里是目录↓↓↓,点击直达哦~

  • 前言
  • 一、QLibrary简介
  • 二、常用方法
    • 2.1 构造函数
    • 2.2 设置要访问的动态库——setFileName()
    • 2.3 加载动态库——load()
    • 2.4 获取动态库的名字——fileName()
    • 2.5 解析共享库中的符号——resolve()
  • 三、示例(Demo)
    • 3.1 动态库DLL源码
    • 3.2 主程序部分
    • 3.3 运行结果

在这里插入图片描述

前言

本文代码测试环境:

编程语言构建套件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 运行结果

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1997237.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

入门学习使用overleaf和latex

文章目录 1.下载对应的latex论文模板2.overleaf平台的使用2.1overleaf平台的介绍2.2overleaf平台模板文件的上传2.3latex语法的学习2.3.2 分段(如下图显示)2.3.3 其他2.3.4简单latex实操2.3.5 换行符和换页符2.3.6左右居中对齐2.3.7 字体设置2.3.8插入固定位置图片2.3.9文字包围…

KillWxapkg 自动化反编译微信小程序,小程序安全评估工具,发现小程序安全问题,自动解密,解包,可还原工程目录,支持修改Hook,小程序

纯Golang实现&#xff0c;一个用于自动化反编译微信小程序的工具&#xff0c;小程序安全利器&#xff0c;自动解密&#xff0c;解包&#xff0c;可还原工程目录&#xff0c;支持微信开发者工具运行 由于采用了UPX压缩的软件体积&#xff0c;工具运行时可能会出现错误报告&…

Springboot整合Flowable入门-学习笔记

目录 1、定义流程&#xff08;画图&#xff09; 2、Springboot部署流程 3、Springboot删除所有流程 4、Springboot根据 流程部署ID 查询 流程定义ID 5、Springboot启动(发起)流程 6、Springboot查询任务 6.1全部任务 6.2我的任务&#xff08;代办任务&#xff09; 7、…

Ubuntu怎么进入救援模式或单用户模式

进入救援模式&#xff08;Rescue Mode&#xff09;或单用户模式&#xff08;Single User Mode&#xff09;的方法取决于你所使用的Linux发行版。以下是通用的步骤&#xff0c;适用于大多数基于GRUB引导的系统&#xff0c;如Ubuntu、Debian、CentOS等&#xff1a; 重启你的系统。…

【Python第三方库】Requests全面解析

文章目录 安装基本用法测试网站发送GET请求发送POST请求更多请求请求参数请求头其他常用请求属性处理响应响应状态码响应内容 处理超时处理异常 requests 是一个非常流行的 Python HTTP 库&#xff0c;用于发送所有类型的 HTTP 请求。它简洁易用&#xff0c;能够处理复杂的请求…

DAMA学习笔记(十三)-大数据和数据科学

1.引言 大数据不仅指数据的量大&#xff0c;也指数据的种类多&#xff08;结构化的和非结构化的&#xff0c;文档、文件、音频、视频、流数据等&#xff09;&#xff0c;以及数据产生的速度快。数据科学家是指从从数据中探究、研发预测模型、机器学习模型、规范性模型和分析方法…

数据结构与算法基础篇--有向无环

. - 力扣&#xff08;LeetCode&#xff09; 力扣-207题 要判定一个图是否为有向无环图&#xff08;DAG, Directed Acyclic Graph&#xff09;&#xff0c;可以使用拓扑排序&#xff08;Topological Sort&#xff09;的方法。如果一个有向图存在拓扑排序&#xff0c;那么它就是…

【MySQL】事务——事务的引入、事务的概念、什么是事务、为什么会出现事务、事务的版本支持、事务的提交方式、事务常见操作方式

文章目录 MySQL1. 事务的引入2. 事务的概念2.1 什么是事务2.2 为什么会出现事务2.3 事务的版本支持2.4 事务的提交方式2.5 事务常见操作方式2.5.1 测试事务开始和回滚2.5.2 测试未commit事务回滚2.5.3 测试commit事务持久化2.5.4 测试begin事务不受自动提交影响2.5.5 测试单条S…

【C++】模板(相关知识点讲解 + STL底层涉及的模板应用)

目录 模板是什么&#xff1f; 模板格式 模板本质 函数模板 格式介绍 显式实例化 模板参数匹配原则 类模板 类模板的实例化 非类型模板参数 模板特化——概念 函数模板特化 类模板的特化 全特化 半特化 偏特化 三种类特化例子&#xff08;放一起比较&#xff09;…

在 CentOS 7 上安装 Redmine 的详细步骤及 20 个经典用法

目录 1. 引言 2. 安装步骤 2.1 更新系统 2.2 安装依赖包 2.3 安装 MariaDB 数据库 2.4 配置 MariaDB 2.5 安装 Ruby 2.6 安装 Redmine 2.7 配置 Redmine 2.8 安装 Bundler 和必要的 Gems 2.9 生成密钥并迁移数据库 2.10 配置 Apache 2.11 启动 Apache 并设置开机自…

1712系列 嵌入式电源系统

1712系列 嵌入式电源系统 2/3/4/5G&共享站点快速部署 简述 1712A 300A嵌入式电源系统采用模块化设计、组合式结构&#xff0c;由控制器、整流模块、交流配电单元、直流配电单元等组成。该系统将交流电转换成稳定的-48V直流电&#xff0c;用于铁塔、移动、电信、联通等公司…

修改nacos实力权重或者对某实例下线报错

在Nacos控制台进行上述操作&#xff0c;错误信息 caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused:…

sql注入大总结【万字详解】

文章目录 数据库的架构sql注入概念正常语句正常回显页面在页面中使用sql语句 跨库查询sql文件读写影响条件复现读写的路径的问题 sql注入请求分类sql注入请求类型sql注入请求方式&#xff1a;sql注入数据请求格式 数据库的增删改查数据库查询数据库添加数据库删除数据库修改 盲…

【python函数】读文件(返回str数据)

大家好&#xff0c;我是一名_全栈_测试开发工程师&#xff0c;已经开源一套【自动化测试框架】和【测试管理平台】&#xff0c;欢迎大家关注我&#xff0c;和我一起【分享测试知识&#xff0c;交流测试技术&#xff0c;趣聊行业热点】。 一、函数说明&#xff1a; 使用的函数&a…

STM32IIC与SPI详解

单片机里的通信协议其实蛮多的&#xff0c;IIC&#xff1b;SPI&#xff1b;MQTT&#xff1b;CAN&#xff1b;包括串口也是一种通信协议。而串口通信虽然实现了全双工&#xff0c;但需要至少三根线&#xff0c;为了节省这一根线的成本&#xff0c;于是IIC诞生了。 目录 一.IIC…

【产业前沿】树莓集团如何以数字媒体产业园为引擎,加速产业升级?

在数字化转型的浪潮中&#xff0c;树莓集团以敏锐的洞察力和前瞻性的战略眼光&#xff0c;将数字媒体产业园打造成为产业升级的强劲引擎。这一创新举措不仅为传统行业插上了数字的翅膀&#xff0c;更为整个产业链注入了新的活力与可能。 树莓集团深知&#xff0c;数字媒体产业园…

【人工智能】AI最终会取代程序员吗?

1. 前言 到 2030 年&#xff0c;40% 的编程任务将实现自动化。这个令人难以置信的统计数据凸显了人工智能在软件工程中日益增长的影响力&#xff0c;并引发了一个问题&#xff1a;人工智能会彻底接管软件工程吗&#xff1f; 人工智能技术正在蓬勃发展&#xff0c;有望实现大量…

【实战】Spring Security Oauth2自定义授权模式接入手机验证

文章目录 前言技术积累Oauth2简介Oauth2的四种模式授权码模式简化模式密码模式客户端模式自定义模式 实战演示1、mavan依赖引入2、自定义手机用户3、自定义手机用户信息获取服务4、自定义认证令牌5、自定义授权模式6、自定义实际认证提供者7、认证服务配置8、Oauth2配置9、资源…

C语言程序设计-[11] 循环结构嵌套

1、循环结构嵌套形式 上面三种循环语句结构可以相互嵌套&#xff0c;组合非常灵活。循环嵌套需要记住最重要的一点&#xff1a;”外循环执行一次&#xff0c;内循环要完整执行一遍”&#xff0c;要通过实例加深对这一句话的理解。 注1&#xff1a;一个循环结构由四个要素构成&…

Java设计模式-建造者模式-一次性理解透

1. 建造者模式简介 今天我们将研究 Java 中的建造者模式&#xff08;Builder 模式&#xff09;。Builder 设计模式是一种创建型设计模式&#xff0c;也被称为生成器模式&#xff0c;类似于工厂模式和抽象工厂模式。 该模式用于创建复杂对象&#xff0c;允许用户创建不同类型的…