QT调VC的DLL实验总结

来源:互联网 发布:arch linux 安装教程 编辑:程序博客网 时间:2024/05/16 12:05

        本文主要介绍”如何在Qt程序中调用VC的DLL库“,包括:隐式加载和显式加载、编译选项、导出函数、调用约定和错误分析。

一、开发环境

1,Qt5.4.1 + MinGW Compiler,生成Caller程序。

2,VS2015,生成win32 DLL库。


二、隐式加载

1,新建VC的DLL

        使用VS2015新建win32 DLL项目 —— TestDll。添加如下代码:

// TestDll.cpp : 定义 DLL 应用程序的导出函数。//#include "stdafx.h"extern "C"  int __declspec(dllexport) __stdcall Foo(int a, int b){    return a + b;}

        1)它使用C方式导出函数。

        2)它使用__stdcall调用约定,VS默认为__cdecl,故此处要显示注明。


2,新建Qt的Caller.exe

        使用QCreator新建Qt控制台应用程序。并进行如下修改:

1)在.pro文件添加导出库的.lib文件所在位置和名字。如下:

LIBS += -L $$_PRO_FILE_PWD_/Lib -l TestDll
        它实际上就是添加了一条编译命令 —— LIBS,其中附带选项”-L“(大写),其值为.lib文件所在目录。我在此使用的是”$$_PRO_FILE_PWD“宏,其中前两个符号是路径抽取符,后面的宏是指.pro所在路径,同时,我需要在该路径下新建一个文件夹”Lib“,并把”TestDll.lib“文件放在里面。此外,需要注意的是,Qt中的路径字符串遵循Linux标准,使用的是斜杠(slash),Windows实际使用反斜杠(backslash)。

        该编译命令的第二个选项是”-l"(小写),它指定.lib文件名,不带后缀,这样可以兼容Windows下的.dll和Linux下的.so文件。

2)在“main.cpp”中声明被调函数。

extern "C" int __stdcall Add(int, int);
        在实际项目中,可以直接包含导出库的.h文件。但是,需要指定.h文件的路径,它需要在.pro中添加“INCLUDEPATH”编译命令。


3)调用测试

        在main函数中直接调用

int result = Add(2, 3)


4)将TestDll.lib文件拷贝到上面指定目录下。


5)将TestDll.dll文件拷贝到运行目录下,即和Caller.exe在同一个目录下。


        如此,程序即可正常编译和运行,并可debug查看正确调用后的结果 —— “result 的值为5”。


3,错误分析

1)如果没有将.lib文件放到指定位置,编译时将报链接错误,找不到指定的lib文件。

2)如果函数导出方式(extern ”C“)不一致,或者调用约定不一致(__stdcall或__cdecl),编译时将报链接错误,找不到指定的导出函数。

3)如果.dll文件没有放到”可执行文件目录“,不会报编译错误,在运行时将弹错误框“执行失败”,并显示“During startup programexited with code 0xc0000135”。

        综上,隐式加载方式在编译阶段会去解析.lib文件,并将导出函数符号链接到程序中。而真正的库函数,是在程序启动阶段进行加载。


三、显式加载

        Qt显式加载主要是利用QLibrary类。

QLibrary lib("TestDll");lib.load();int result = 0;if (lib.isLoaded()){    typydef int(*FuncPtr)(int, int);    FuncPtr pFunc = (FuncPtr)lib.resolve("Add");    if (pFunc)        result = pFunc(2, 3);}

1)它实际上是在运行时通过resolve函数去.dll文件中找导出函数符“Add",找到后返回该函数的地址,实际上是一个偏移量。

2)可以用void*去接收resolve的返回值,后面调用的时候再转换为对应的函数指针。

3)该方法在我的实验来看,只适合”__cdecl“调用约定导出的函数,如果DLL中的函数使用”__stdcall“方式导出,resolve函数的返回值为”0"。即使将函数指针声明为如下形式:

typydef int(__stdcall*FuncPtr)(int, int);
因为,实际上是resolve函数没有解析出相关的导出函数。


相关参考:


Qt5中动态链接库的创建和使用


Qt调用VC的DLL


上文提到的“隐式调用"的方法:

LIBS += -L *** -I ***

该方法只适合MinGw编译器,VC编译器直接用”#pragma comment(lib, "***")",否则报错:

LNK1146:没有选项“:LIBSPATH"指定的参数


命令行编译参考:GccHowTo 和 从C++到Qt

0 0