二十四、Qt之使用动态库

在 Qt 中,动态库又叫共享库

一、当只有 dll 库 、 头文件时的引入方式

步骤和下面基本一致,唯一的就是配置文件的差异,配置文件如下:

#头文件目录
INCLUDEPATH += $$PWD/include
#设置添加的库文件
LIBS += -L$$PWD/include/ -llibqjson-qt5

二、当有 dll库 、 头文件 、 lib库 文件时的引入方式

(一)、调用动态库之方式一:隐式链接调用动态库

备注:应用程序的编译器版本+位数必须与动态库的编译器版本+位数一致,才能编译通过!!比如动态链接库是在 MSVC2015+32bit 环境编译的,那么应用程序的编译环境也必须是 MSVC2015+32bit。

第一步:收集

在项目的源文件目录下创建一个 include 子目录,将库的头文件 qwdialogpen.h 、mysharedlib_global.h、插件的 debug 和 release 两种模式编译生成的库文件 mySharedLibd.lib 和 mySharedLib.lib 复制到此目录下,项目在编译链接时需要此头文件和库文件。

备注:动态库在debug编译时,生成的 lib 文件不会带 d 结尾,需要手动在文件名后加 “d”!生成的 dll 文件暂时不要动,也不要改变命名,等后面复制到可执行文件的目录下。

第二步:导入库文件

方式一:引导方式

右击项目,在弹出的菜单中选择 “添加库…” ,选择库类型时,选择 外部库“External Library”;选择库文件位置时,就把 include 文件夹下的 mySharedLib.lib 选中即可,会自动填充 “Include path”编辑框,选择 windows 平台,连接方式选择 Dynamic(动态链接库,插件是Dynamic) ,勾选下方 Add “d” suffix for debug version,表示在 debug 版本的库名称后面添加一个字母 “d”,以便编译器自动区分 release 和 debug 版本的库文件。

方式二:手动代码导入

修改项目文件 sharedLibUser.pro,添加:

MSVC编译模式:
#设置添加的库文件,会判断当前项目时以 debug 还是 release 模式编译
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lmySharedLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lmySharedLib
#头文件目录
INCLUDEPATH += $$PWD/include
#项目依赖目录
DEPENDPATH += $$PWD/include

这样只有MSVC编译器可以编译

MinGw 编译模式:
win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/libmySharedLib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/libmySharedLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/mySharedLib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/mySharedLib.lib

这样只有 MinGW编译器可以编译

MSVC + MinGw 两种编译模式:
#设置添加的库文件,会判断当前项目时以 debug 还是 release 模式编译
win32:CONFIG(release, debug|release): LIBS += -L$$PWD/include/ -lmySharedLib
else:win32:CONFIG(debug, debug|release): LIBS += -L$$PWD/include/ -lmySharedLib
#头文件目录
INCLUDEPATH += $$PWD/include
#项目依赖目录
DEPENDPATH += $$PWD/include

win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/libmySharedLib.a
else:win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/libmySharedLibd.a
else:win32:!win32-g++:CONFIG(release, debug|release): PRE_TARGETDEPS += $$PWD/include/mySharedLib.lib
else:win32:!win32-g++:CONFIG(debug, debug|release): PRE_TARGETDEPS += $$PWD/include/mySharedLib.lib

这样 MSVC 和 MinGW编译器都可以编译

第四步:引入头文件,并使用

#include "qwdialogpen.h"

第五步:编译项目

编译

在 debug 和 release 两种模式下分别编译。

将两种模式编译生成的 dll 文件分别复制到对应的可执行文件的目录下
E:\Qt_Demo\build-shareLibUser-Desktop_Qt_5_9_0_MSVC2015_32bit-Debug\debug
E:\Qt_Demo\build-shareLibUser-Desktop_Qt_5_9_0_MSVC2015_32bit-Release\release

备注:debug 模式下编译生成的 dll 文件名千万不要变动(末位加 “d”),保持原样,否则会报错!!!

第六步:运行项目

(二)、调用动态库之方式二:显式链接调用动态库

显示链接调用共享库是应用程序运行时才加载共享库文件,并调用库里的函数的。应用程序编译时无需共享库的任何文件,只需知道函数名和函数的原型即可。所以,这种方式可以调用其他语言编写的 dll 文件。
显示链接调用共享库是通过 QLibrary 类实现的,在 QLibrary 的构造函数中传递一个文件名,也可以是不带后缀的单独文件名。QLibrary 会根据运行的平台自动查找不同后缀的共享库文件,例如 Unix 上是 “.so”,Mac上是“.dylib”,Windows 上是 “.dll”。
一个动态链接库在内存里只有一个实例,也就是说即使有多处调用了这个动态链接库里的函数,它也只会被载入一次,如果不是所有的实例都调用 unload() 卸载它,那么它会在应用程序退出时才卸载。
案例:
用 Delphi 编写一个 dll 项目,生成一个 DelphiDLL.dll 文件,这个文件里只有一个函数,函数原型为:

function triple(N:integer):integer;

它会计算传递参数 N 的3倍值并返回。

void MyMainWindow::on_btnTrigger_clicked()
{
    //初始化 QLibrary
    QLibrary myLib("DelphiDLL");
    //判断是否加载入内存
    if (myLib.isLoaded())
        QMessageBox::information(this, "信息", "DelphiDLL.dll 已经被载入,第1处");
    //声明 dll 中函数原型
    typedef int (*FunDef)(int);
    //解析 dll 中函数
    FunDef myTriple = (FunDef) myLib.resolve("triple");
    //调用函数
    int value = myTriple(ui->spinBoxInput->value());
    ui->spinBoxOutput->setValue(value);
    //判断是否加载入内存
    if (myLib.isLoaded())
        QMessageBox::information(this, "信息", "DelphiDLL.dll 已经被载入,第2处");
}

在案例中,第一次点击按钮时,只有第2处信息框显示,说明初始化了 QLibrary 之后,动态链接库没有立即被载入内存;第二次单击时,会出现两个信息框,说明动态链接库至上次载入内存中后,一直在内存中。
在案例中,我们即使不将调用的 dll 文件不放入可执行程序中,编译和运行也不会报错,只有点击按钮触发加载时才会报错,所以我们需要将 dll 文件复制到可执行文件夹下!!!

  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个简单的例子,演示了如何在Qt中创建和使用动态库动态库工程代码(mylib.pro): ``` TEMPLATE = lib CONFIG += dll QT += core gui HEADERS += mylib_global.h \ myclass.h SOURCES += myclass.cpp \ mylib_global.cpp TARGET = mylib DESTDIR = ../bin ``` mylib_global.h文件: ```cpp #ifndef MYLIB_GLOBAL_H #define MYLIB_GLOBAL_H #include <QtCore/qglobal.h> #if defined(MYLIB_LIBRARY) # define MYLIB_EXPORT Q_DECL_EXPORT #else # define MYLIB_EXPORT Q_DECL_IMPORT #endif #endif // MYLIB_GLOBAL_H ``` myclass.h文件: ```cpp #ifndef MYCLASS_H #define MYCLASS_H #include "mylib_global.h" #include <QObject> class MYLIB_EXPORT MyClass : public QObject { Q_OBJECT public: explicit MyClass(QObject *parent = nullptr); Q_INVOKABLE void doSomething(); }; #endif // MYCLASS_H ``` myclass.cpp文件: ```cpp #include "myclass.h" #include <QDebug> MyClass::MyClass(QObject *parent) : QObject(parent) { } void MyClass::doSomething() { qDebug() << "MyClass::doSomething() called."; } ``` 使用动态库的程序代码: ```cpp #include <QCoreApplication> #include <QLibrary> #include "myclass.h" int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); // 加载动态库 QLibrary myLib("mylib.dll"); if(!myLib.load()) { qDebug() << "Failed to load library."; } // 获取MyClass类的指针 MyClass *myClass = (MyClass*)myLib.instance(); if(myClass == nullptr) { qDebug() << "Failed to get MyClass instance."; } else { // 调用MyClass的函数 myClass->doSomething(); } return a.exec(); } ``` 需要注意的是,在编译使用动态库的程序时,需要在.pro文件中添加LIBS += -lmylib或者LIBS += ../lib/mylib.dll(取决于动态库文件的名称和路径)。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值