zoukankan      html  css  js  c++  java
  • Qt下开发及调用带界面的DLL

    0.背景

    由于某项目需要,在Qt下开发及调用带界面的DLL。由于中间折腾时间较长才搞定,在这记录一下。
    本帖子中所用Qt版本为QtCreator 4.10.2.基于Qt5.13.2(MSVC 2017,32位)

    1. Qt DLL开发

    1.1 工程建立

    新建工程,选择:Library->C++ Library在工程细节中Qt module中选择 Widgets,如下图所示:

    生成的项目中文件列表如下:

    其中,在LaerRangerDLL_globall.h中,定义了宏
    # define LASERRANGERDLL_EXPORT Q_DECL_EXPORT
    查看Q_DECL_EXPORT的定义可以看出# define Q_DECL_EXPORT __declspec(dllexport)
    该定义即为dll导出符号的宏定义。

    1.2 添加窗体

    新建窗体,选择Qt->Qt 设计师界面类,如下图所示:

    选Main Window,并添加到之前的项目:

    在窗体中加入一个Label,并修改显示字符串为:LaserRangerDLL
    然后修改LaserRangerDLL的头文件和源文件:
    头文件中做如下修改:

    头文件中添加ui_mainwindow.hQWidget头文件
    并将给LaserRangerDLL类添加基类:QMainWindow,并修改其构造函数原型。
    添加私有成员:Ui::MainWindow ui;
    修改源文件如下:

    在构造函数里添加ui.setupUi(this);

    1.3 生成DLL

    在项目上点击右键:构建,生成DLL和Lib。
    则在工程对应的Debug(或Release,和构建配置有关)文件夹里生成LaserRangerDLL.dll和LaserRangerDLL.lib文件。

    2. 调用DLL

    DLL调用分为两种:隐式调用和显式调用。
    其中,隐式调用是在编译时包含.lib文件和.h头文件,这两个文件中包含了动态库中导出的接口信息。然后,在运行时调用dll中封装的二进制代码。
    显式调用只有.dll,在运行时通过代码显式的加载dll文件,声明函数原型,并使用dll中的接口。

    2.1 隐式调用

    以第1建立的动态库项目LaserRangerDLL为例,建立LaserRangerCaller项目,来调用生成的DLL。

    在项目文件夹下建立include文件夹,并将生成的LaserRangerDLL.liblaserrangerdll.hLaserRangerDLL_global.hui_mainwindow.h拷贝进include文件夹。
    注意:ui_mainwindow.h需要将dll的项目编译后,在build文件夹中找到
    如下图所示:

    然后,在LaserRangerCaller工程中头文件中加入include文件夹

    添加完之后如下图所示:

    然后再在项目上右击,依次"添加库"->"外部库",库文件定位到LaserRangerDLL.lib,链接选动态。注意,在Windows选项中去掉为debug版本添加‘d’作为后缀的勾选(该选项默认为选中)。
    如下图所示:

    先编译一遍LaserRangerCaller工程。
    并将生成的dll文件拷贝进该工程的builddebug文件夹中。
    然后在main.cpp中加入头文件引用和对象调用。

    然后运行laserRangerCaller,出现如下窗口:

    证明隐式调用成功。

    2.2 显式调用

    显式调用共享库通过QLibrary类实现,QLibrary类可以实现动态库中的导出函数加载,相关成员函数如下:
    load():用于手动载入DLL文件到内存里,一般无需手动调用此函数,在DLL里的函数第一次被使用时QLibrary会自动调用从函数

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

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

    resolve():解析DLL文件中的函数
    这些函数的详细解析可以看Qt的帮助文档。
    下面通过例程,对第1部分生成的dll进行显式调用。
    新建一个Qt Widget工程LaserRangerLoader
    并自动生成一个MainWindow窗体,在窗体中加入一个按钮, 命名成pushButton_dll_loader

    • 加入接口函数
      注意要通过显式调用的话,只能调用导出函数,所以在laserrangerdll工程中加入导出函数:
      在头文件中加入:
    extern "C" {
        LASERRANGERDLL_EXPORT LaserRangerDLL* getLaserRangerDLLObj();
    
        LASERRANGERDLL_EXPORT const char* disp();
    
        LASERRANGERDLL_EXPORT int addInt(int a,int b);
    }
    

    注意,由于C++具有多态特性,可能会给函数名在编译时添加其他后缀,所以在此用extern "C"关键字,保证导出符号与定义函数名一致。
    然后在源文件里也加入对应实现代码:

    LaserRangerDLL* getLaserRangerDLLObj()
    {
        return new LaserRangerDLL();
    }
    
    const char* disp()
    {
        return "This is a test function for LaserRangerDLL";
    }
    
    int addInt(int a,int b)
    {
        return a+b;
    }
    

    然后编译dll工程
    在工程目录下建立include文件夹,并将laserrangerdll.hLaserRangerDLL_global.hui_mainwindow.h拷贝进include文件夹。
    编译一下该工程,将动态库LaserRangerDLL.dll放入编译后的build目录的debug目录下。

    • 显式调用
      pushButton_dll_loader的槽函数中加入dll的加载和调用。
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    #include "QLibrary"
    #include "QDebug"
    #include "iostream"
    #include "QMessageBox"
    #include "./include/laserrangerdll.h"
    
    typedef LaserRangerDLL* (*getLaserRangerDLLObj_fcn)();
    typedef const char* (disp_fcn)();
    typedef int (intAdd_fcn)(int,int);
    
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    }
    
    MainWindow::~MainWindow()
    {
        delete ui;
    }
    
    
    void MainWindow::on_pushButton_dll_loader_clicked()
    {
        QLibrary* laser_ranger_dll_lib = new QLibrary("LaserRangerDLL.dll");
        if(laser_ranger_dll_lib->load())
        {
            getLaserRangerDLLObj_fcn get_obj_fcn = (getLaserRangerDLLObj_fcn)
                    laser_ranger_dll_lib->resolve("getLaserRangerDLLObj");
            LaserRangerDLL* laser_ranger_dll = get_obj_fcn();
            laser_ranger_dll->show();
        }
    }
    

    然后运行,点击按钮,则出现dll中的窗体。

    给孤独的理想插上自由的翅膀
  • 相关阅读:
    今日遇到一问题,甚是定奇怪,我将文件名称改为小写,系统便能载入上,但为何这样呢?
    CCCardinalSplineBy概念
    Java基本开发环境搭建
    Webserver推送技术
    十一招解决:系统IE部分网页打不开怎么办(转载)
    UIControl-IOS开发
    Sublime Text 2 介紹
    java的System.getProperty()方法能够获取的值
    IBinder对象在进程间传递的形式(一)
    cocos2d-x 3.0游戏实例学习笔记 《跑酷》 完结篇--源代码放送
  • 原文地址:https://www.cnblogs.com/spyplus/p/widget_dll_in_qt.html
Copyright © 2011-2022 走看看