各位看官这里是目录↓↓↓,点击直达哦~
- 前言
- 一、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++ 11 | Desktop Qt 5.9.9 MSVC2013 64bit | Qt Creator 4.11.0 | Windows10 |
一、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
",在macOS
和iOS
上为“.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。
注意事项:
- 该方法有隐式加载的行为。即:如果动态库尚未被加载,调用
resolve()
方会隐式地尝试加载动态库。这是通过调用load()
方法实现的,调用者不需要关心或处理这个加载过程的细节,QLibrary
会在内部处理这些细节。 - 解析的符号必须作为
C
函数从库中导出,这意味着如果使用C++
编译器编译库,函数需要被封装在extern C
块中。 - 在
Windows
平台上,还需要使用__declspec(dllexport)
宏来显示导出函数。
根据注意事项第2、第3条,给出以下示例代码 ↓ ↓ ↓:
extern "C"
{
__declspec(dllexport) int avg(int a, int b)
{
return (a + b) / 2;
}
}
三、示例(Demo)
看完以上内容,写个Demo
练习巩固下。
Demo
具体内容分为动态库部分和主程序部分:
- 动态库:实现一个加法运算,将传递进来的数值相加,并将结果传回;
- 主程序:使用
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();
}