Qt5 共享库(创建与使用)

创建Qt共享库

1、+New Project
2、项目 - Library - c++库 - choose
3、类型 - 共享库
4、名称 - dll1 - 下一步
5、编译器选择 (我是MinGW32)- 下一步
6、选择需要的模块 (我只默认选了 Qt Core)- 下一步
7、类信息(默认就行了)- 下一步
8、项目管理(同上)- 完成
9、生成目录树

dll1
    dll1.pro
    头文件
        dll1.h
        dll1_global.h
    源文件
        dll1.cpp

10、当前文件源码
- dll1.pro

#-------------------------------------------------
#
# Project created by QtCreator 2018-06-26T10:07:39
#
#-------------------------------------------------

QT       -= gui

TARGET = dll1
TEMPLATE = lib

DEFINES += DLL1_LIBRARY

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += dll1.cpp

HEADERS += dll1.h\
        dll1_global.h

unix {
    target.path = /usr/lib
    INSTALLS += target
}
  • dll1.h
#ifndef DLL1_H
#define DLL1_H

#include "dll1_global.h"

class DLL2SHARED_EXPORT Dll1
{

public:
    Dll1();
};

#endif // DLL1_H
  • dll1_global.h
#ifndef DLL1_GLOBAL_H
#define DLL1_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(DLL1_LIBRARY)
#  define DLL1SHARED_EXPORT Q_DECL_EXPORT
#else
#  define DLL1SHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // DLL1_GLOBAL_H
  • dll1.cpp
#include "dll2.h"


Dll2::Dll2()
{
}

11、关键字介绍

dll1.pro

qmake 的工程(project)文件

dll1.h

主头文件

dll1_global.h

基本概念:符号 - 函数、变量或类 - 包含在供客户端(例如:应用程序或其他库)使用的共享库中,必须以一种特殊的方式标记。这些符号被称为公共符号,它们被导出或公开可见。
使用方法:在编译共享库时,必须将其标记为EXPORT。为了在客户端使用共享库,一些平台可能需要一个特殊的IMPORT声明。

为此,Qt 提供了两个特殊的宏:

 - Q_DECL_EXPORT:当编译共享库时,必须将其添加到使用的符号声明。
 - Q_DECL_IMPORT:当编译一个(使用了该共享库)客户端时,必须将其添加到使用的符号声明。

结论:
要确保正确的宏能够被调用(无论是编译共享库本身,还是在客户端使用共享库),通常通过添加一个特殊的头文件({projectName}_global.h)来解决,这就是 {projectName}_global.h 存在的原因。

dll1.cpp

源文件

TARGET

指定库的名称

TEMPLATE

模板的意思,将其指定为 lib,是要告诉 qmake 我们需要生成的是一个库文件(app 为可执行程序)。

DEFINES

用于定义编译选项

SOURCES

源文件名字(要包含后缀)

HEADERS

头文件名字(要包含后缀)

INSTALLS

要安装的文件

Q_DECL_EXPORT

导出

Q_DECL_IMPORT

导入

12、当前工程的所有文件改动如下

dll1_global.h
拷贝该文件中的代码 至 头文件dll1.h,然后删除该文件(彻底删除也没关系):
#include <QtCore/qglobal.h>

#if defined(DLL1_LIBRARY)
#  define DLL1SHARED_EXPORT Q_DECL_EXPORT
#else
#  define DLL1SHARED_EXPORT Q_DECL_IMPORT
#endif

dll1.h
在public部分声明函数
void HelloWorld(QString str);

dll1.cpp
添加以下代码
#include <QDebug>
void Dll2::HelloWorld(QString str)
{
    qDebug()<<str<<endl;
}

最后,点击构建,即可生成输出。
Note1:在 Windows 中,有动态链接库(DLL - Dynamic Link Library);在 Linux 中,有共享库(Shared Library),它们是相同的!
Note2:由于平台和编译器的差异,输出的库文件也不同:在 Windows 中,MinGW 将输出 .a.dll;MSVC 将输出 .lib.dll。在 Linux 中,MinGW 将输出 .so.so.1.so.1.0.so.1.0.0 - .lib;其中.lib .a .so 是导入库,它们有助于将我们的代码链接到库中,并且在构建文件时需要。
Note3: Debug 版本(带 d)为 SharedLibd.lib 和 SharedLibd.dll,Release 版本(不带 d)为 SharedLib.lib 和 SharedLib.dll

创建Test测试共享库的导入及其API调用

1、+New Project
2、项目 - Application - Qt Console Application - choose
3、名称 - Testdll1 - 下一步
4、编译器选择 (我是MinGW32)- 下一步
5、项目管理(同上)- 完成
6、生成目录树

Testdll1
    Testdll1.pro
    源文件
        main.cpp

7、当前文件源码

Testdll1.pro

QT += core
QT -= gui

CONFIG += c++11

TARGET = Testdll1
CONFIG += console
CONFIG -= app_bundle

TEMPLATE = app

SOURCES += main.cpp

# The following define makes your compiler emit warnings if you use
# any feature of Qt which as been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

main.cpp

#include <QCoreApplication>

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    return a.exec();
}

8、导入共享库 dll1 的方法


一、使用Qt Creator提供的方法:
1、编译当前工程,生成debug/release输出文件
2、点击工程
3、右键添加库,选择外部库
4、选择库文件(我选择.a),配置当前对话框信息(我平台选择windows,链接选择动态,Windows选择为debug版本添加"d"作为后缀)
5、拷贝 (dll1D.dll / dll1.dll)至 Testdll1 的Debug路径下(我的是..\build-Testdll1-Desktop_Qt_5_8_0_MinGW_32bit-Debug\debug)
6、在工程添加 dll1.h 
7、已经可以在工程中使用 dll1.dll 了,例如在Testdll1.cpp中包含 dll1.h 头文件,再创建dll1的对象或指针,即可通过指针或对象,调用 dll1 的 API 了。

使用方法如下:
#include <QCoreApplication>
#include "dll1.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);
    Dll1 dll;
    dll.HelloWorld("HelloWorld");
    return a.exec();
}
二、通过 windows 提供的 API 调用
1、编译当前工程,生成debug/release输出文件
2、cpp如下:

#include <windows.h>
int main()
{
    //首先定义函数指针,用来接收不同参数的函数
    // 第一个关键字 typedef 定义类型模板
    // 第二个关键字 可以为其他类型,主要是调用的函数的类型,例如调用int main()就定义int类型的函数指针
    // 第三个关键字 CALLBACK 是定义回调函数类型的指针,名字用于后续调用Dll API
    // 第四个关键字 是函数的参数,例如 int main()没有参数,则不定义类型,注意只需要声明参数的类型即可,而不需要参数名字
    typedef int (CALLBACK *Fucv)();
    typedef int (CALLBACK *Fuci)(int);
    typedef int (CALLBACK *Fucii)(int,int);

    //获得.dll文件的句柄,需要头文件windows.h的支持
    HINSTANCE hdll=LoadLibrary(L"Dll1.dll");     //L指宽字符串,若不写L,则会出现错误,详情请自查

    //注意这里要用 dll函数查看器 查看到的函数名
    Fucv t1=(Fucv)GetProcAddress(hdll,"_Z5test1v");
    Fucv t2=(Fucv)GetProcAddress(hdll,"_Z5test2v");
    Fuci t3=(Fuci)GetProcAddress(hdll,"_Z5test3i");
    Fucii t4=(Fucii)GetProcAddress(hdll,"_Z5test4ii");

    //现在的t1就执行的test1的功能,以此类推
    t1();
    t2();
    t3(1);
    t4(1,2);

    //因为dll本身是没有内存的,上面我们主动分配了,这里用完就要释放dll内存
    FreeLibrary(hdll);
}

dll函数查看器

总结

1、还是方法一好用….

PS

后期我有关于 库 的知识更新时,会来更新该博文的

猜你喜欢

转载自blog.csdn.net/dennis_sck/article/details/80810995