QT调VC的DLL实验总结
2016-05-26 16:43
337 查看
本文主要介绍”如何在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
一、开发环境
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
相关文章推荐
- QT与数据库连接
- LR11如何打开回放结果窗口 “Results.qtp”,
- Qt 的sqlite数据库的学习
- NANOPI2 编译QT+sqlite 问题解决方式
- 详解 Qt 4访问Sqlite数据库
- Qt布局管理: 堆栈窗体QStackedWidget类(纯代码实现)
- 为什么Qt编程出现No signal?
- qt在Windows下调用动态库
- qt在Windows下生成包含动态库的动态库
- Qt-MapX
- Qt获取系统默认图标,显示到QListWidget内
- Qt5.1.0 MinGW480 release静态版编译结果及过程分享
- Qt 4.8.4中文显示问题
- 【opencv学习之二】opencv与qt图像格式交换IplImage-->QImage
- Qt简易计算器的代码实现
- Qt的皮肤设计(Style Sheet)
- 从 Qt 的 delete 说开来
- ubuntu下配置qt+opengl+opencv
- VS2013 Qt5 Mysql中文编码问题
- Qt 多线程与数据库操作需要注意的几点问题