zoukankan      html  css  js  c++  java
  • QT创建和使用动态链接库

    转载于:Qt:56---QT创建和使用动态链接库(.dll)_董哥的黑板报-CSDN博客

    一、QT的动态链接库

    QT的动态链接库编译后生成DLL文件(本文只讲解Windows下的动态库文件)

    DLL文件是在应用程序运行时才加载的,不像静态库那样在编译期就编到应用程序里。若更新了DLL文件,只要接口未变,应用程序依然可以调用

    使用动态链接库可以很方便地扩展应用程序的功能,但是DLL文件需要随应用程序一起发布,并且编译DLL和应用程序的Qt版本最好保持一致,否则考虑二进制兼容问题

     

    二、动态链接库的创建

    第一步:

    点击“File”的“New File or Project”,然后选择下面的“C++ Library”

     

     

    第二步:

    选择动态库,然后将项目命名为“mySahredLib”

     

     

    然后选择编译器

     

     

    接着选择项目中需要的Qt模块

     

     

    然后将类名设置为“QWDialogPen”

     

     

    第三步:

    生成的项目起初有以下几个文件

     

     

    其中有一个特殊的mySahredLib_global.h,其内容如下。MYSAHREDLIBSHARED_EXPORT符号用于替换Qt的Q_DECL_EXPORT宏或Q_DECL_IMPORT宏(一个共享库导出给用户使用的类、符号、函数等都需要用宏Q_DECL_EXPORT来定义导出,一个使用共享库的应用程序都需要通过Q_DECL_IMPORT导入共享库里的可用对象)

    #include <QtCore/qglobal.h>

     

    #if defined(MYSAHREDLIB_LIBRARY)

    #  define MYSAHREDLIBSHARED_EXPORT Q_DECL_EXPORT

    #else

    #  define MYSAHREDLIBSHARED_EXPORT Q_DECL_IMPORT

    #endif

    .pro中增加了MYSAHREDLIB_LIBRARY符号

     

     

    qwdialogpen.h中的类名前使用了MYSAHREDLIBSHARED_EXPORT,定义QWDialogPen为一个导出的类

     

     

    第四步:

    此时我们开始实现动态库需要实现的功能

    与上篇静态库文章一样,我们将另外一个项目的文件复制到这个动态库项目的目录下,并覆盖同名文件(另外一个项目是一个画笔设置对话框,类名与文件名都与本次动态库的名称一致)

     

     

    在.h文件中加上#include "mysahredlib_global.h"头文件,类名前加上MYSAHREDLIBSHARED_EXPORT宏(因为复制过来的文件没有这些内容)

     

     

    右击项目,将.ui文件也添加进项目中

     

     

    第五步:

    项目准备好之后,就可以准备编译生成DLL文件了,根据使用的编译器不用,有如下区别

     

    若使用MSVC编译:编译后会生成myShreadLib.dll和myShreadLib.lib两个文件。myShreadLib.dll在运行应用程序时调用,myShreadLib.lib在应用程序隐式调用动态链接库时使用

    若使用MinGW编译:编译后会生成myShreadLib.dll和myShreadLib.a两个文件,myShreadLib.dll在运行应用程序时调用,myShreadLib.a在应用程序隐式调用动态链接库时使用

    采用debug和release不同模式生成的文件只能在应用程序的debug或release模式下编译或调用

     

    此处,我们在MSVC2015 64bit下编译,并且debug和release都编译一次

     

     

    编译后会产生这个对话框,不需要理会

     

     

    在项目的debug和release的build文件夹下都生成了相应的文件

     

     

    三、动态链接库的使用

    动态链接库有2种调用方式:

     

    ①隐式链接:在编译应用程序时,有动态库的lib文件(或.a文件)和.h头文件,知道DLL中有哪些接口类和函数,编译时就隐式地生成必要的链接信息,使用DLL中的类或函数时根据.h头文件中的定义使用即可。应用程序运行时将自动加载DLL文件。隐式链接调用主要用于同一种编程软件(如Qt)生成的代码的共享

    ②显示链接:调用只有DLL文件,知道DLL里的函数原型,使用QLibrary类对象在应用程序里动态加载DLL文件,声明函数原型,并使用DLL里的函数。这种方式需要在应用程序里声明函数原型,并解析DLL力的函数

    隐式调用共享库

    第一步:创建一个基于QMainWindows的应用程序“shareLibUser”,类名采用默认值即可

    第二步:在项目目录下新建一个include目录(此目录名称自己设计),将动态库项目的两个头文件复制到此目录下。若使用MSVC编译器,则将rlease版本的mySharedLib.lib复制include目录下,debug版本的mySharedLib.lib更名为mySharedLibd.lib复制到include目录下;若使用MinGW编译器,则复制release版本的mySharedLib.a,debug版本的mySharedLib.a更名为mySharedLibd.a然后放入include目录下

     

     

    为了程序的正常运行,还需要将动态库在debug和release版本编译产生的.dll文件,分别置于项目的可执行文件(.exe)的debug和release目录下(否则,程序运行时会出错)

     

     

     

     

     

    第三步:在项目中添加动态链接库。右击项目“Add Library...”,然后选择“External Libraary”,在向导第二步设置导入的动态库文件

     

     

    然后会在.pro文件中增加如下内容

     

     

    项目编译时,会根据当前是release还是debug模式,自动添加相应的库文件。这里添加库文件只是抵用了动态库的导出定义,而不是将库的实现代码连接到应用程序的可执行文件里

     

    第四步:在项目中,导入动态库头文件,就可以使用相关类和函数了

     

     

    第五步:开始设计项目,在类中添加以下代码

     

     

    第六步:实现paintEvent函数

    void MainWindow::paintEvent(QPaintEvent *event)

    {

        Q_UNUSED(event);

        QPainter painter(this);

        QRect rect(0,0,width(),height());

        painter.setViewport(rect);

        painter.setWindow(0,0,100,50);

        painter.setPen(mPen);

        painter.drawRect(10,10,80,30);

    }

    第七步:设计一个Action工具栏按钮,并实现triggered函数

     

     

    void MainWindow::on_action_Pen_triggered()

    {

        bool ok=false;

        QPen pen=QWDialogPen::getPen(mPen,ok);

        if(ok)

        {

            mPen=pen;

            this->repaint();

        }

    }

    第七步:运行程序,调用成功

     

     

    显式链接共享库(QLibrary类)

    特点:显式链接调用共享库是在应用程序运行时才加载共享库文件,并调用库里的函数的。应用程序编译时无需共享库的任何文件,只需知道函数名和函数的原型即可。所以,这种方式可以调用其他语言编写的DLL文件,例如用Delphi生成的一个DLL文件

    QLibrary类

     

    头文件:#include <QLibrary>

    显式链接调用共享库是通过QLibrary类实现的。QLibrary是与平台无关的,用于在运行时载入共享库,一个QLibrary对象只对一个共享库进行操作

    构造函数:传入一个文件名,可以是带路径的绝对文件名,也可以是不带后缀的单独文件名(当不带后缀的单独文件名时,QLibrary会在应用程序同一目录、系统目录、或可搜索目录下查询这个“文件名.dll”文件)

    如果.dll文件没有复制到应用程序目录下,编译和启动应用程序都不会出错,但是当调用动态库中的内容时就会出错,因此要是应用程序正常运行,需要将.dll文件复制到应用程序目录下

    一个动态链接库在内存里只能有一个实例,也就是即使有多处调用了这个动态链接库里的函数,它也只会被载入一次,如果不是所有的实例都是用unload()卸载它,那么它在应用程序退出时才卸载

    QLibrary类相关函数

     

    load():用于手动载入DLL文件到内存里,一般无需手动调用此函数,在DLL里的函数第一次被使用时QLibrary会自动调用从函数

    isLoaded():用于判断DLL是否已经被载入内存

    unload():用于将DLL从内存中卸载

    resolve():解析DLL文件中的函数,见下面的演示案例

    演示案例

     

    第一步:作为案例,我们用C++编写一个DLL项目,生成一个shareLib.dll文件,这个文件中只有一个函数,用于返回参数num的3倍值(如何生成C++ DLL文件,见文章:https://blog.csdn.net/qq_41453285/article/details/83420541)

     

     

    第二步:创建了一个基于QMainWindow的QT项目,项目名为“userShareLib”,类名采取默认值。然后将生成的动态库文件放在QT项目的当前目录下

     

     

    第三步:设置UI界面,用于输入一个值,然后通过调用DLL文件,输出3倍数值

     

     

    第四步:显示按钮的clicked函数

    void MainWindow::on_pushButton_clicked()

    {

        QLibrary myLib("shareLib.dll");

        if(myLib.isLoaded())

            QMessageBox::information(this,QStringLiteral("信息"),

                QStringLiteral("shareLib.dll已经被载入,在1处"));

        

        typedef int (*FunDef)(int); //需要声明函数原型的类型

        FunDef myTriple=(FunDef)myLib.resolve("triple"); //解析DLL中的triple函数

     

        int V=myTriple(ui->spinInput->value());//调用函数

        ui->spinOutput->setValue(V);

        

        if(myLib.isLoaded()) //查看动态库文件是否还在程序的内存中

            QMessageBox::information(this,QStringLiteral("信息"),

                 QStringLiteral("shareLib.dll已经被载入,在2处"));

    }

    ————————————————

    版权声明:本文为CSDN博主「董哥的黑板报」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

    原文链接:https://blog.csdn.net/qq_41453285/article/details/100087495

    一、QT的动态链接库

    QT的动态链接库编译后生成DLL文件(本文只讲解Windows下的动态库文件)

    DLL文件是在应用程序运行时才加载的,不像静态库那样在编译期就编到应用程序里。若更新了DLL文件,只要接口未变,应用程序依然可以调用

    使用动态链接库可以很方便地扩展应用程序的功能,但是DLL文件需要随应用程序一起发布,并且编译DLL和应用程序的Qt版本最好保持一致,否则考虑二进制兼容问题

     

    二、动态链接库的创建

    第一步:

    • 点击“File”的“New File or Project”,然后选择下面的“C++ Library”

    image.png

    第二步:

    • 选择动态库,然后将项目命名为“mySahredLib”

    image.png

    然后选择编译器

    image.png

    接着选择项目中需要的Qt模块

    image.png

    然后将类名设置为“QWDialogPen”

    image.png

     

    第三步:

    • 生成的项目起初有以下几个文件

    •  

    image.png

     

    其中有一个特殊的mySahredLib_global.h,其内容如下。MYSAHREDLIBSHARED_EXPORT符号用于替换Qt的Q_DECL_EXPORT宏或Q_DECL_IMPORT宏(一个共享库导出给用户使用的类、符号、函数等都需要用宏Q_DECL_EXPORT来定义导出,一个使用共享库的应用程序都需要通过Q_DECL_IMPORT导入共享库里的可用对象)

    C++
    #include <QtCore/qglobal.h>
     
    #if defined(MYSAHREDLIB_LIBRARY)
    #  define MYSAHREDLIBSHARED_EXPORT Q_DECL_EXPORT
    #else
    #  define MYSAHREDLIBSHARED_EXPORT Q_DECL_IMPORT
    #endif

    .pro中增加了MYSAHREDLIB_LIBRARY符号

    image.png

    qwdialogpen.h中的类名前使用了MYSAHREDLIBSHARED_EXPORT,定义QWDialogPen为一个导出的类

    image.png

    第四步:

    • 此时我们开始实现动态库需要实现的功能

    • 与上篇静态库文章一样,我们将另外一个项目的文件复制到这个动态库项目的目录下,并覆盖同名文件(另外一个项目是一个画笔设置对话框,类名与文件名都与本次动态库的名称一致)

    image.png

    在.h文件中加上#include "mysahredlib_global.h"头文件,类名前加上MYSAHREDLIBSHARED_EXPORT宏(因为复制过来的文件没有这些内容)

    image.png

    • 右击项目,将.ui文件也添加进项目中

       

    image.png

    第五步:

    项目准备好之后,就可以准备编译生成DLL文件了,根据使用的编译器不用,有如下区别

     

    若使用MSVC编译:编译后会生成myShreadLib.dll和myShreadLib.lib两个文件。myShreadLib.dll在运行应用程序时调用,myShreadLib.lib在应用程序隐式调用动态链接库时使用

    若使用MinGW编译:编译后会生成myShreadLib.dll和myShreadLib.a两个文件,myShreadLib.dll在运行应用程序时调用,myShreadLib.a在应用程序隐式调用动态链接库时使用

    采用debug和release不同模式生成的文件只能在应用程序的debug或release模式下编译或调用

     

    此处,我们在MSVC2015 64bit下编译,并且debug和release都编译一次

    image.png

    编译后会产生这个对话框,不需要理会

    image.png

    在项目的debug和release的build文件夹下都生成了相应的文件

    image.png

    image.png

    三、动态链接库的使用

    动态链接库有2种调用方式:

     

    ①隐式链接:在编译应用程序时,有动态库的lib文件(或.a文件)和.h头文件,知道DLL中有哪些接口类和函数,编译时就隐式地生成必要的链接信息,使用DLL中的类或函数时根据.h头文件中的定义使用即可。应用程序运行时将自动加载DLL文件。隐式链接调用主要用于同一种编程软件(如Qt)生成的代码的共享

    ②显示链接:调用只有DLL文件,知道DLL里的函数原型,使用QLibrary类对象在应用程序里动态加载DLL文件,声明函数原型,并使用DLL里的函数。这种方式需要在应用程序里声明函数原型,并解析DLL力的函数

     

    隐式调用共享库

    第一步:创建一个基于QMainWindows的应用程序“shareLibUser”,类名采用默认值即可

    第二步:在项目目录下新建一个include目录(此目录名称自己设计),将动态库项目的两个头文件复制到此目录下。若使用MSVC编译器,则将rlease版本的mySharedLib.lib复制include目录下,debug版本的mySharedLib.lib更名为mySharedLibd.lib复制到include目录下;若使用MinGW编译器,则复制release版本的mySharedLib.a,debug版本的mySharedLib.a更名为mySharedLibd.a然后放入include目录下

    image.png

    为了程序的正常运行,还需要将动态库在debug和release版本编译产生的.dll文件,分别置于项目的可执行文件(.exe)的debug和release目录下(否则,程序运行时会出错)

    image.png

    image.png

    第三步:在项目中添加动态链接库。右击项目“Add Library...”,然后选择“External Libraary”,在向导第二步设置导入的动态库文件

    image.png

    然后会在.pro文件中增加如下内容

    image.png

     

    项目编译时,会根据当前是release还是debug模式,自动添加相应的库文件。这里添加库文件只是抵用了动态库的导出定义,而不是将库的实现代码连接到应用程序的可执行文件里

    • 第四步:在项目中,导入动态库头文件,就可以使用相关类和函数了

    image.png

    第五步:开始设计项目,在类中添加以下代码

     

    image.png

    第六步:实现paintEvent函数

    C++
    void MainWindow::paintEvent(QPaintEvent *event)
    {
        Q_UNUSED(event);
        QPainter painter(this);
        QRect rect(0,0,width(),height());
        painter.setViewport(rect);
        painter.setWindow(0,0,100,50);
        painter.setPen(mPen);
        painter.drawRect(10,10,80,30);
    }

    第七步:设计一个Action工具栏按钮,并实现triggered函数

    image.png

    C++
    void MainWindow::on_action_Pen_triggered()
    {
        bool ok=false;
        QPen pen=QWDialogPen::getPen(mPen,ok);
        if(ok)
        {
            mPen=pen;
            this->repaint();
        }
    }

    第七步:运行程序,调用成功

    image.png

     

    显式链接共享库(QLibrary类)

    特点:显式链接调用共享库是在应用程序运行时才加载共享库文件,并调用库里的函数的。应用程序编译时无需共享库的任何文件,只需知道函数名和函数的原型即可。所以,这种方式可以调用其他语言编写的DLL文件,例如用Delphi生成的一个DLL文件

    QLibrary类

     

    头文件:#include <QLibrary>

    显式链接调用共享库是通过QLibrary类实现的。QLibrary是与平台无关的,用于在运行时载入共享库,一个QLibrary对象只对一个共享库进行操作

    构造函数:传入一个文件名,可以是带路径的绝对文件名,也可以是不带后缀的单独文件名(当不带后缀的单独文件名时,QLibrary会在应用程序同一目录、系统目录、或可搜索目录下查询这个“文件名.dll”文件)

    如果.dll文件没有复制到应用程序目录下,编译和启动应用程序都不会出错,但是当调用动态库中的内容时就会出错,因此要是应用程序正常运行,需要将.dll文件复制到应用程序目录下

    一个动态链接库在内存里只能有一个实例,也就是即使有多处调用了这个动态链接库里的函数,它也只会被载入一次,如果不是所有的实例都是用unload()卸载它,那么它在应用程序退出时才卸载

    QLibrary类相关函数

     

    load():用于手动载入DLL文件到内存里,一般无需手动调用此函数,在DLL里的函数第一次被使用时QLibrary会自动调用从函数

    isLoaded():用于判断DLL是否已经被载入内存

    unload():用于将DLL从内存中卸载

    resolve():解析DLL文件中的函数,见下面的演示案例

    演示案例

     

    第一步:作为案例,我们用C++编写一个DLL项目,生成一个shareLib.dll文件,这个文件中只有一个函数,用于返回参数num的3倍值(如何生成C++ DLL文件,见文章:https://blog.csdn.net/qq_41453285/article/details/83420541)

     

    image.png

    第二步:创建了一个基于QMainWindow的QT项目,项目名为“userShareLib”,类名采取默认值。然后将生成的动态库文件放在QT项目的当前目录下

    image.png

     

    • 第三步:设置UI界面,用于输入一个值,然后通过调用DLL文件,输出3倍数值

    •  

    image.png

    第四步:显示按钮的clicked函数

    C++
    void MainWindow::on_pushButton_clicked()
    {
        QLibrary myLib("shareLib.dll");
        if(myLib.isLoaded())
            QMessageBox::information(this,QStringLiteral("信息"),
                QStringLiteral("shareLib.dll已经被载入,在1处"));
        
        typedef int (*FunDef)(int); //需要声明函数原型的类型
        FunDef myTriple=(FunDef)myLib.resolve("triple"); //解析DLL中的triple函数
     
        int V=myTriple(ui->spinInput->value());//调用函数
        ui->spinOutput->setValue(V);
        
        if(myLib.isLoaded()) //查看动态库文件是否还在程序的内存中
            QMessageBox::information(this,QStringLiteral("信息"),
                 QStringLiteral("shareLib.dll已经被载入,在2处"));
    }
  • 相关阅读:
    left join
    order by 对null的处理
    checkbox不显示,试试去掉-webkit-appearance这个样式
    浅谈ES6的let和const的异同点
    ES6中箭头函数的作用
    HTML页面每次打开的时候都清除页面缓存
    解决HTML加载时,外部js文件引用较多,影响页面打开速度问题
    JQuery和Zepto的差异(部分)
    vue-router 快速入门
    vue-resource插件使用
  • 原文地址:https://www.cnblogs.com/tingtaishou/p/15206090.html
Copyright © 2011-2022 走看看