QT中dll的生成及使用

C++中的库分为三种:静态库、动态库和导入库

1、静态库:

    静态库扩展名为.lib,静态链接(即代码会直接编译进可执行文件)。静态库是一个或多个obj文件的打包。

2、动态库和导入库

    和静态库不同,动态库不会编译进可执行文件中,多个程序引用动态库时,内存中实际只会有一份动态库的内容。
    用QT创建动态库时,实际生成两个文件,一个lib文件和一个dll文件,这个lib文件就是导入库。

    导入库是动态库的辅助库,导入库中不含代码,而是为链接程序提供信息,包含在.exe文件中建立动态链接时要用到的重定位表。

    导入库用于程序开发时,动态库用于程序运行时。

3、在项目中使用动态库的方法

1) 隐式加载

    这种方式和静态库的使用方法一样,注意此时要包含的是导入库而不是动态库,依然需要头文件,代码中可直接使用头文件中的函数名,并且这种方式在运行时需要动态库。

2) 显式加载(又称运行时动态链接):

    如果使用windows接口,则在代码中使用LoadLibrary()显式打开dll文件,使用GetProcAddress获取函数地址然后使用,使用完之后用FreeLibrary显式释放dll文件。这种方式不需要导入库及.h文件。
    在QT中则可以使用QLibrary的load方法。
    注:使用隐式加载时,如果进程在启动时未找到dll,则操作系统将终止此进程。但使用显式加载时则进程不会被终止。
    以上参考:https://blog.csdn.net/finewind/article/details/44959039
https://www.jianshu.com/p/8743a0edb1ee

4、隐示加载dll demo

创建一个TestDll项目,创建项目的时候选择 Library->C++库


image.png

pro文件

QT       -= gui

TARGET = TestDll
TEMPLATE = lib

DEFINES += TESTDLL_LIBRARY

SOURCES += testDll.cpp

HEADERS += testdll.h\
        testdll_global.h \
    basetest.h

unix {
    target.path = /usr/lib
    INSTALLS += target
}

testDll.h

#ifndef TESTDLL_H
#define TESTDLL_H
#include "basetest.h"
#include "testdll_global.h"

class TESTDLLSHARED_EXPORT TestDll : public BaseTest
{

public:
    TestDll();

    virtual int add(int a, int b);
};

extern "C" {
    TESTDLLSHARED_EXPORT BaseTest *getObj();
}

#endif // TESTDLL_H

basetest.h

#ifndef BASETEST
#define BASETEST

class BaseTest
{

public:
    BaseTest() {}

    virtual int add(int a, int b) = 0;
};

#endif // BASETEST

testdll_global.h

#ifndef TESTDLL_GLOBAL_H
#define TESTDLL_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(TESTDLL_LIBRARY)
#  define TESTDLLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define TESTDLLSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // TESTDLL_GLOBAL_H

testDll.cpp

#include "testdll.h"


TestDll::TestDll()
{
}

int TestDll::add(int a, int b)
{
    return a + b;
}

BaseTest *getObj()
{
    return new TestDll();
}

构建之后会在build同时生成一个.lib和.dll文件


image.png

TestDll.lib即为导出库

创建一个DllUser项目

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = DllUser
TEMPLATE = app


SOURCES += main.cpp\
        mainwindow.cpp

INCLUDEPATH += include

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

LIBS += lib/TestDll.lib

CONFIG(debug, debug|release){
    DESTDIR = bin/Debug
} else {
    DESTDIR = bin/Debug
}

在该工程的根目录下创建一个lib文件夹,将dll的导出库拷贝到该目录
在根目录下创建一个include文件夹,将dll的头文件拷贝到该目录
并将TestDll.dll拷贝至DllUser.exe的同级目录


image.png

mainwindow.cpp代码:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "include/testdll.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    int a = ui->lineEdit->text().toInt();
    int b = ui->lineEdit_2->text().toInt();

    TestDll obj;
    int sum = obj.add(a, b);
    QString str = QString::number(sum);
    ui->label->setText(str);
    ui->label->show();
}

5、显示加载dll demo

    显示加载如果只是导出一个函数比较简单,但是如果要导出一个类的话稍微有些麻烦,该demo主要演示如何从dll中导出一个类。
    首先,定义一个BaseTest抽象类作为TestDll的基类,BaseTest的头文件需要在使用Dll的项目中引用
DLL的项目代码在4中已展示
下面创建一个显示加载该dll的项目DllLoad, pro文件如下:

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = DllLoad
TEMPLATE = app

INCLUDEPATH += include


SOURCES += main.cpp\
        mainwindow.cpp

HEADERS  += mainwindow.h

FORMS    += mainwindow.ui

CONFIG(debug, debug|release){
    DESTDIR = bin/Debug
} else {
    DESTDIR = bin/Debug
}

注意需要在该项目的根目录下创建include目录,并将抽象类BaseTest的头文件basetest.h拷贝到该文件夹下,DllLoad不需要再引用dll的其他头文件
mainwindow.cpp的代码

#include <QApplication>
#include <QLibrary>
#include <QDebug>
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "include/basetest.h"

typedef BaseTest* (*Get_Obj)(); //定义函数指针,以备调用
BaseTest *g_obj = NULL;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    loadDll();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::loadDll()
{
    QLibrary testLib("TestDll.dll");
    if (testLib.load()) {
        Get_Obj getObj = (Get_Obj)testLib.resolve("getObj");
        if (getObj) {
            qDebug()<<"getObj";
            g_obj = getObj();
        }
    }
}

void MainWindow::on_pushButton_clicked()
{
    int a = ui->lineEdit->text().toInt();
    int b = ui->lineEdit_2->text().toInt();

    if (g_obj) {
        int sum = g_obj->add(a, b);
        QString str = QString::number(sum);
        ui->label->setText(str);
        ui->label->show();
    }
}

将TestDll.dll拷贝至exe同级目录即可运行
所有代码已上传至:https://download.csdn.net/download/boo12355/11071455
以上参考:
https://blog.csdn.net/yysdsyl/article/details/2626109
编写DLL所学所思(2)——导出类
DLL导出类避免地狱问题的完美解决方案
dll导出类比较好的方式:(https://blog.csdn.net/qiangzi4646/article/details/79628260

引:
https://blog.csdn.net/u012150179/article/details/12346555
https://www.cnblogs.com/weizhixiang/p/6698532.html
https://blog.csdn.net/xuebing1995/article/details/78230626
https://blog.csdn.net/wb175208/article/details/86181626
http://blog.sina.com.cn/s/blog_713542d30102wxxj.html

C++中模块(DLL)对外暴露接口的几种方式:
https://blog.csdn.net/liubing8609/article/details/78906784

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343