Qt DLL总结【二】-创建及调用QT的 DLL
开发环境:VS2008+Qt4.7.4
最近看了不少Qt的DLL例子,总结一下如何创建和调用QT 动态链接库。
先讲一下对QT动态链接库的调用方法,主要包括:
1、显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法
2、显示链接DLL,调用DLL中类对象、成员函数。(通过对象即可实现类成员函数的调用)
①用虚函数表的方法,这也是COM使用的方法,利用Qt的QLibrary技术调用;
②用GetProcAddress直接调用。
③用Qt的QPluginLoader类直接调用生成的DLL插件类对象
3、隐式链接DLL:也是采用Qt的Qlibrary方法
关于这种三种方法,下面详细叙说
详细分类叙述
前提:两个项目文件目录
1、TestDLL项目:testdll_global.h,TestDll.h,TestDll.cpp
2、TestMain exe应用项目:main.cpp
testdll_global.h 文件源代码一直不变
- #ifndef TESTDLL_GLOBAL_H
- #define TESTDLL_GLOBAL_H
- #include <QtCore/qglobal.h>
- #ifdef TESTDLL_LIB
- # define TESTDLL_EXPORT Q_DECL_EXPORT
- #else
- # define TESTDLL_EXPORT Q_DECL_IMPORT
- #endif
- #endif // TESTDLL_GLOBAL_H
DLL的显式链接在某些时候比隐式链接具有更大的灵活性。比如,如果在运行时发现DLL无法找到,程序可以显示一个错误信息并能继续运行。当你想为你的程序提供插件服务时,显式链接也很有用处
1、采用显示链接,调用DLL中全局函数,只需要一个TestDLL.dll。
通常Windows下程序显示调用dll的步骤分为三步(三个函数):LoadLibrary()、GetProcAdress()、FreeLibrary()
其中,LoadLibrary() 函数用来载入指定的dll文件,加载到调用程序的内存中(DLL没有自己的内存!)
GetProcAddress() 函数检索指定的动态链接库(DLL)中的输出库函数地址,以备调用
FreeLibrary() 释放dll所占空间
而QT的QLibrary类显示链接调用DLL的步骤:load()、resolve(const char * symbol )、unload()和VC步骤类似
TestDll.dll项目中的TestDLL.h源码
- #ifndef TESTDLL_H
- #define TESTDLL_H
- #include "testdll_global.h"
- class TESTDLL_EXPORT TestDll
- {
- public:
- TestDll();
- ~TestDll();
- private:
- };
- extern "C" TESTDLL_EXPORT void helloWorld();
- extern "C" TESTDLL_EXPORT int add(int a,int b);
- #endif // TESTDLL_H
TestDll.dll项目中的TestDLL.cpp源码
- #include <iostream>
- #include "TestDll.h"
- TestDll::TestDll()
- {
- }
- TestDll::~TestDll()
- {
- }
- void helloWorld()
- {
- std::cout << "hello,world!";
- }
- int add(int a,int b)
- {
- return a + b;
- }
注:1)建立成功DLL项目后,可以在VS命令提示行中用命令"dumpbin -exports DllTest.dll"来查看(也可以用VC工具包中的depends使用程序来查看)
注:2)必须使用extern "C"链接标记,否则C++编译器会产生一个修饰过的函数名,这样导出函数的名字将不再是helloworld,而是一个形如" ?helloWorld@TestDll@@UAEXXZ”的名字。为什么名字不是helloworld呢?这是因为C++为了支持函数的重载,会在编译时将函数的参数类型信息以及返回值类型信息加入到函数名中,这样代码中名字一样的重载函数,在经过编译后就互相区分开了,调用时函数名也经过同样的处理,就能找到对应的函数了。详细可以看这篇文章动态链接库(Dynamic Link Library)学习笔记
TestMain项目 main.cpp
- #include <QtCore/QCoreApplication>
- #include <iostream>
- #include <QLibrary>
- typedef int (*Fun)(int,int); //定义函数指针,int add(int a,int b);
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
- QLibrary mylib("TestDll.dll"); //声明所用到的dll文件
- int result;
- //判断是否正确加载
- if (mylib.load())
- {
- std::cout << "DLL load is OK!"<<std::endl;
- //调用外部函数 add()
- Fun add = (Fun)mylib.resolve("add");
- //是否成功连接上 add() 函数
- if (add)
- {
- std::cout << "Link to add Function is OK!"<<std::endl;
- //这里函数指针调用dll中的 add() 函数
- result = add(5,6);
- std::cout << result;
- }
- else
- std::cout << "Link to add Function failed!!"<<std::endl;
- }
- //加载失败
- else
- std::cout << "DLL is not loaded!"<<std::endl;
- return a.exec();
- }
2、采用显示链接,调用C++类中的类对象、成员函数
如果你想导出并显式链接一组C++类中的成员函数又该怎么办呢?这里有两个问题。第一是C++成员函数名是经过修饰的(即使指定extern "C"标记也是这样);第二是C++不允许将指向成员函数的指针转换成其它类型。这两个问题限制了C++类的显式链接。下面介绍两种方法来解决这个问题:
①用虚函数表的方法,这也是COM使用的方法,利用Qt的QLibrary技术调用;
②用GetProcAddress直接调用。
③用Qt的QPluginLoader类直接调用生成的DLL插件类对象
①虚函数表的方法,QLibrary 技术调用
TestDll.h代码
- #ifndef TESTDLL_H
- #define TESTDLL_H
- #include "testdll_global.h"
- class TESTDLL_EXPORT TestDll
- {
- public:
- TestDll();
- virtual~TestDll();
- virtual void helloWorld(); //类成员函数
- private:
- };
- extern "C" TESTDLL_EXPORT TestDll* getTestDll(); //获取类TestDll的对象
- #endif // TESTDLL_H
TestDll.cpp源码
- #include <iostream>
- #include "TestDll.h"
- TestDll::TestDll()
- {
- }
- TestDll::~TestDll()
- {
- }
- void TestDll::helloWorld()
- {
- std::cout << "hello,world!";
- }
- TestDll* getTestDll()
- {
- return new TestDll();
- }
TestMain项目中的main.cpp源码
- #include <QtCore/QCoreApplication>
- #include <iostream>
- #include <QLibrary>
- #include "../TestDll/TestDll.h" //头文件还是需要加的,否则无法解析TestDll类
- typedef TestDll* (*GetTestDll)();//定义函数指针,获取类TestDLL对象;
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
- QLibrary mylib("TestDll.dll"); //声明所用到的dll文件
- int result;
- //判断是否正确加载
- if (mylib.load())
- {
- GetTestDll getTestDll = (GetTestDll)mylib.resolve("getTestDll");
- if(getTestDll)
- {
- TestDll *testDll = getTestDll();
- testDll->helloWorld();
- delete testDll;
- }
- }
- //加载失败
- else
- std::cout << "DLL is not loaded!"<<std::endl;
- return a.exec();
- }
这个方法的使用得用户可以很容易地为你的程序制作插件。它的缺点是创建对象的内存必须在dll中分配
②用GetProcAddress直接调用类对象中的成员函数
这个方法,我没测试,对我没对大作用,还得用def导出DLL函数,有兴趣的就参考一下这篇文章。DLL中类的显式链接
③用Qt的QPluginLoader类直接调用生成的DLL插件类对象
这个方法,我单独写一篇总结,请看QPluginLoader的简单小例子VS2008+Qt 使用QPluginLoader访问DLL
3、采用隐式链接方法,通过QLibrary类对DLL中类对象、全局函数的调用
TestDll.h
- #ifndef TESTDLL_H
- #define TESTDLL_H
- #include "testdll_global.h"
- class TESTDLL_EXPORT TestDll
- {
- public:
- TestDll();
- ~TestDll();
- void helloWorld(); //类成员函数
- private:
- };
- extern "C" TESTDLL_EXPORT int add(int a,int b); //自定义的外部函数
- #endif // TESTDLL_H
TestDll.cpp源码
- #include <iostream>
- #include "TestDll.h"
- TestDll::TestDll()
- {
- }
- TestDll::~TestDll()
- {
- }
- void TestDll::helloWorld()
- {
- std::cout << "hello,world!";
- }
- int add(int a,int b)
- {
- return a + b;
- }
TestMain项目中的main.cpp ,需要稍微配置头文件和lib文件
1、在项目中主程序引入TestDll.h头文件,
2、配置项目属性:加入TestDLL.lib的文件目录,在Linker/General/Additional Library Diretories里面选择TestDll.lib的文件目录D:\VSWorkSpace\Test\Debug
3、配置项目属性:加入TestDll.lib文件,在Linker/Input/Additional Dependencies 中加入 TestDll.lib
main.cpp源码
- #include <QtCore/QCoreApplication>
- #include <iostream>
- #include <QLibrary>
- #include "../TestDll/TestDll.h"
- //引入TestDll.lib文件,和上面的2,3步工作同理
- //#pragma comment(lib, "../Debug/TestDll.lib")
- int main(int argc, char *argv[])
- {
- QCoreApplication a(argc, argv);
- int result = add(5,6);
- std::cout << result;
- TestDll dll;
- dll.helloWorld();
- return a.exec();
- }
结果即可编译成功
Qt DLL总结【二】-创建及调用QT的 DLL的更多相关文章
- Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good
目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...
- qt 创建及调用QT的 DLL
先讲一下对QT动态链接库的调用方法,主要包括: 1.显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法 2.显示链接DLL,调用DLL中类对象.成员函数.(通过对象即可实现类成员函数 ...
- QT共享库的创建与调用(初级)(附:UI界面不能被改变的其中一个原因)
背景: 最近在做的一个项目其中一部分既是实现PC与下位机的USB通信.windows平台下已经完成,现需移植到linux平台下. 在linux系统中,通过一段时间的工作,设备已被配置成hid类(后续再 ...
- Qt Lighthouse学习(二),就是QPA(Qt Platform Abstraction) 项目的名字
上一次关注Qt Lighthouse是在6月初,可是现在都8月底了.时间真快... Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新 ...
- Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问DLL
目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...
- delphi dll创建及调用
第一章 DLL简单介绍由于在目前的学习工作中,需要用到DLL文件,就学习了下,在这里作个总结.首先装简单介绍下DLL:1,减小可执行文件的大小DLL技术的产生有很大一部分原因是为了减小可执行文件的大小 ...
- 关于c#调用c/c++ dll遇到的问题总结
前段时间公司做了个winform程序,需要调用c 的dll去读取卡号的程序,期间遇到些问题,下面来分享下 一.dll路径问题 相信很多开发者都会遇到这个问题,我总结了下我现在有3总方式去解决这个问题: ...
- Qt Dll总结(二)——创建及使用Qt的Dll(转载)
先讲一下对QT动态链接库的调用方法,主要包括: 1.显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法 2.显示链接DLL,调用DLL中类对象.成员函数.(通过对象即可实现类成员函数 ...
- QT创建与调用Dll方法(包括类成员)--显式调用
看网上的好多关于QT调用Dll的方法,大部分都是调用函数的,并没有调用C++类成员的情况,即使是有,比如说: 使用Qt编写模块化插件式应用程序 Qt 一步一步实现dll调用(附源码)---(这一篇里没 ...
随机推荐
- Centos7.7安装expect命令工具
简单介绍 expect是一个免费的编程工具,用来实现自动的交互式任务,而无需人为干预.说白了,expect就是一套用来实现自动交互功能的软件. 在实际工作中,我们运行命令.脚本或程序时,这些命令.脚本 ...
- 【Struts2】进阶
一.Action处理请求参数 1.1 属性驱动 1.2 模型驱动 1.3 扩展 将数据封装到List集合 将数据封装到Map集合 二.类型转换 2.1 自定义类型转换器: 1.创建一个自定义类型转换器 ...
- 前端基础(一):HTML内容
HTML介绍 Web服务本质 import socket sk = socket.socket() sk.bind(("127.0.0.1", 8080)) sk.listen(5 ...
- new Function()语法
函数的语法: let func = new Function(...args, body); 历史原因,参数也可以以逗号分隔的列表的形式给出,这三个意思相同: new Function('a', 'b ...
- VS---《在VS2010中 使用C++创建和使用DLL》(003)
VS---<在VS2010中 使用C++创建和使用DLL>(003) 这里实现一下,之前写好的一个工程(定义一个函数f + main函数调用),转成DLL.调用DLL测试.在两个工程里,分 ...
- Google 的Web开发相关工具
一.PageSpeed Insights PageSpeed Insights 能够针对移动设备和桌面设备生成网页的实际性能报告,并能够提供关于如何改进相应网页的建议. 在线工具:https://de ...
- ext系统的超级块
什么是超级块 如果说inode块是Linux操作系统中文件的核心,那么超级块就是文件系统的心脏.启动Lnux操作系统后,发现某个文件系统无法使用,很有 可能就是超级块出现了问题.为什么这个超级块有这么 ...
- jQuery 查找父节点 parents()与closest()
parents()由内向外,直到最高的父节点停止查找,返回的父节点是多个 closest()由内向外查找,当找到符合规则的一个,则不再查找,返回的是0或1个
- HDU 6057 - Kanade's convolution | 2017 Multi-University Training Contest 3
/* HDU 6057 - Kanade's convolution [ FWT ] | 2017 Multi-University Training Contest 3 题意: 给定两个序列 A[0 ...
- 【Wince-USB通讯】Wince在没有Wifi的情况下使用USB数据线与PC进行Socket通讯
具体操作 1.确保Wince连接PC成功 2.服务端的IP输入:127.0.0.1 ,然后启动侦听. 3.在客户端输入的服务器IP是:192.168.55.100 (客户端的IP是192.168.55 ...