Qt6之调用Windows下vc生成的动态链接库dll

Qt是跨平台工具,显然能和windows的动态库一起使用。

在Windows操作系统上,库以文件的形式存在,并且可以分为动态链接库(DLL) 和静态链接库两种。动态链接库文控以.dll为后缀名,静态链接库文控以.lib为后缀名。不管是动态链接库还是静态链接库,都是向它们的调用者提供变量、函数或举。

实质上,windows系统库主要以dll动态库为主,所以会在C:\Windows\System32下有大量的dll结尾的库文件。

⚠️windows下理论概念比较多适合萌新消化,大佬绕行!

 一、简述动态链接库

动态链接库的源码就是函数或类的具体实现,源码经过编译后会生成一个后缀名为dll的文件,这个文件就是动态链接库文件,是一个二进制形式的文件,不可以单独运行,必须和它的调用者一起运行。它通常可以向其调用者提供变量、函数或类

1、调用者(或称为使用者) 可以是应用程序 (exe程序) 或其他动态链接库;

2、提供给调用者调用的函数通常被称为导出函数;

3、提供给调用者使用的类通常被称为导出类。

动态链接库经过编译后会生成一个.lib文控和一个.dll文件,这里的.lib文件不是指静态链接库文件,而是导入库文文件,虽然后缀名和静态链接库文控相同,但是两者没有任何关系。

从调用来分,又有以下两种区别:

隐式链接:在程序执行的时候,就将DLL文件加载到应用程序中;

显式链接:应用程序在执行过程中随时可以添加DLL文件,也可以随时卸载DLL文件,这是隐式链接无法做到的,所以显示链接具有更好的灵活性,对于解释性言语更为合适。

.lib导入库文件中存放的是DLL文控中导出函数的名称和地址,应用程序采用隐式链接动态链接库时,会把导入库文控中的内容(导出函数或类的名称和地址) 复制到应用程序的代码中,当应用程序运行时,就能知道动态链接库中导出函数(或类) 的地址了。

 二、动态链接库dll的分类

简单的说把DLL分为非MFC DLL(又称Win 32 DLL)MFC DLL

非MFC DLL (Non-MFC DLL) 也称Win32 DLL,它指的是不用MFC的类库结构直接用C或者C++编写的DLL,其导出的函数是标准的C或者c++接口,能被非MFC或MFC编写的应用程序所调用。如果建立的DLL不需要使用MFC,那么应该建立Non-MFC DLL,因为使用MFC会增大用户库的大小,会浪费用户的磁盘和内存空间。

MFC DLL意味着可以在这种DLL的内部使用了微软的MFC库,这种情况不属于本文讨论范围之内;

三、动态链接库dll开发和调用

一个有用的DLL,首先要把DLL中的变量、函数或类导出,再编译生成dll文件。导出就是对那些要给外部程序使用的变量、函数或类进行声明。

通常有两种导出方式:

第一种方式是通过关键字 declspec(dllexport)导出;

另一种是采用模块定义文件.def导入文件(大部分情况下用的少不做演示);

无论采用哪种方法编译,最终都会生成dll文件和lib文件 (导入库文件)。

3.1 通过关键字 declspec(dllexport)导出

使用关键字 declspec(dllexport)可以从DLL导出数据、函数、类或类成员函数。这种方式比较简单,只要导出的内容前加 declspec(dllexport)即可。以下vs中演示第一种:

(1)、vs新建,动态链接库DLL;

 (2)、项目名称,勾选将解决方案和项目放在同一目录;

 (3)、默认会打开dllmain.cpp,直接关闭就行;

 (4)、项目,鼠标右键,添加,类;

(5)、输入类名;

(5)、AddDll.h和AddDll.cpp分别如下;

注意:其类型声明前面加上“__declspec (dllexport)”,为什么这里没有用到类,实测QLibrary调用的win32 dll必须是c语言,如果是C++必用qt自身创建dll。  

 

(6)、一般情况下最终都是需要Release版本都,我这里改Debug为Release,然后生成;

(7)、在项目Release目录下,找到我们需要动态链接库dll文件和lib文件 (导入库文件)

 3.2通过Qt调用dll

Qt调用DLL的导出函数有4种方法:

第一种是使用Win32 API:

第二种是使用Qt自身的API:

第三种是直接调用DLL:

第四种是Qt Creator可视化调用法,点点鼠标即可。

(1)、使用win32api

这种方法主要使用win32的api函数LoadLibrary(), 这种方法已经使用较少了,有兴趣的可参考下文;

(4条消息) 3.利用Win32 API调用DLL_api调用dll方法_深山里的小白羊的博客-CSDN博客icon-default.png?t=N4P3https://blog.csdn.net/qq_33757398/article/details/81564522

(2)、使用Qt自身的API函数QLibrary类

该方法是比较常用的一种,以下演示一下:

需要注意的是QLibrary:: resolve函数中,明确说明,该符号必须作为 C 函数从库中导出。

#include "mainwindow.h"

#include <QApplication>
#include <QLibrary>
#include <QDebug>

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

    QLibrary lib;
    QString str1 = QApplication::applicationDirPath();
    qDebug()<<"str1="<<str1;
    QString str(str1+"/DllTest.dll" );
    lib.setFileName(str);
    if(lib.load())
    {
         typedef int(*AddFunction)(int a,int b);
         AddFunction Add = reinterpret_cast<AddFunction>(lib.resolve("MyAdd"));
         if(!Add)
         {
             qDebug()<<"resolve failed="<<lib.errorString();
         }
         else
         {
             int out=Add(1,3);
             qDebug()<<"out="<<out;
         }
    }
    else
    {
          qDebug()<<"load failed!";
    }

    MainWindow w;
    w.show();
    return a.exec();
}

 (3)、直接调用dll

这种情况下,最省事,但是它需要3个文件,一个lib,一个dll,还需要一个.h文件(源dll)

①将lib拷贝到qt的.pro目录下,如图所示;

 ②将dll复制到生成exe的坐在目录下;

 ③在qt的.pro文件中引用.lib,引用方式如下,-l你的lib文件名;

LIBS+=-L$$PWD/./ -lDllTest

前面表示绝对路径下的当前目录,仅需要修改后面lib名就行,比如你的lib是test123.lib,尾部应该是-ltest123,改完pro文件,记得按ctrl r让qt重新加载;

④添加源dll的头文件,原则上建议,新建一个与.lib同名的.h,这样可以防止编码等问题,如下图先项目右键,添加新文件,然后是C/C++ Header File,输入lib名字,最后将源dll里的头文件函数复制过来并且删除__declspec(dllexport);

 

 ⑤包含上一步新建的头文件,直接调用函数即可;

(4)、Qt Creator可视化调用法

这种方法与上面第三种类似,也是需要.dll和.lib、新建.h头文件,但是这种优势是,qt会自动解决.pro文件的修改。

可先进行这三步①②④,内容都是同第三种方法,把dll和.lib复制到对应位置,新建一个与.lib同名的.h文件并填充内容。

③这步稍微有些不同,如下图,项目右键,添加库,外部库,选择.lib路径后,qt自动解决引用和路径,这在目前看起来好像优势不大,但当你库文件多而杂时,它事半功倍。

 

 ⑤这一步其实也一样,包含头文件,直接调用即可;

 

本文重点还是讨论qt调用vc生成的dll,至于vc之间互相调用更加灵活,可参考以下文章

(4条消息) 在Qt和VS中使用动态链接库.dll文件----以隐式链接的方式_qt vs dll_咖啡与乌龙的博客-CSDN博客icon-default.png?t=N4P3https://blog.csdn.net/qq_40459977/article/details/125652187 原创不易,如有帮助,请多多关注,持续输出更多qt6相关内容!

猜你喜欢

转载自blog.csdn.net/yanchenyu365/article/details/131046583