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++库
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文件
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的同级目录
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