Qt DLL总结-创建及调用QT的 DLL

目录

Qt DLL总结【一】-链接库预备知识

Qt DLL总结【二】-创建及调用QT的 DLL  

Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问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 文件源代码一直不变

 

Cpp代码  收藏代码
  1. #ifndef TESTDLL_GLOBAL_H  
  2. #define TESTDLL_GLOBAL_H  
  3.   
  4. #include <QtCore/qglobal.h>  
  5.   
  6. #ifdef TESTDLL_LIB  
  7. # define TESTDLL_EXPORT Q_DECL_EXPORT  
  8. #else  
  9. # define TESTDLL_EXPORT Q_DECL_IMPORT  
  10. #endif  
  11.   
  12. #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源码

 

Cpp代码  收藏代码
  1. #ifndef TESTDLL_H  
  2. #define TESTDLL_H  
  3.   
  4. #include "testdll_global.h"  
  5.   
  6. class TESTDLL_EXPORT TestDll  
  7. {  
  8. public:  
  9.     TestDll();  
  10.     ~TestDll();   
  11. private:  
  12.   
  13.   
  14. };  
  15. extern "C"   TESTDLL_EXPORT void helloWorld();       
  16. extern "C"   TESTDLL_EXPORT int add(int a,int b);    
  17. #endif // TESTDLL_H  

 

TestDll.dll项目中的TestDLL.cpp源码

 

Cpp代码  收藏代码
  1. #include <iostream>  
  2. #include "TestDll.h"  
  3.   
  4. TestDll::TestDll()  
  5. {  
  6.   
  7. }  
  8.   
  9. TestDll::~TestDll()  
  10. {  
  11.   
  12. }  
  13.   
  14. void helloWorld()  
  15. {  
  16.     std::cout << "hello,world!";  
  17. }  
  18. int add(int a,int b)  
  19. {  
  20.     return a + b;  
  21. }  

   注: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

 

Cpp代码  收藏代码
  1. #include <QtCore/QCoreApplication>  
  2. #include <iostream>  
  3. #include <QLibrary>  
  4.   
  5. typedef int (*Fun)(int,int); //定义函数指针,int add(int a,int b);      
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QCoreApplication a(argc, argv);  
  9.       
  10.     QLibrary mylib("TestDll.dll");   //声明所用到的dll文件  
  11.     int result;  
  12.     //判断是否正确加载  
  13.     if (mylib.load())                
  14.         {  
  15.             std::cout << "DLL load is OK!"<<std::endl;  
  16.             //调用外部函数 add()  
  17.             Fun add = (Fun)mylib.resolve("add");     
  18.             //是否成功连接上 add() 函数  
  19.             if (add)                    
  20.                 {  
  21.                     std::cout << "Link to add Function is OK!"<<std::endl;  
  22.                      //这里函数指针调用dll中的 add() 函数  
  23.                     result = add(5,6);       
  24.                     std::cout << result;  
  25.                 }  
  26.             else  
  27.                 std::cout << "Link to add Function failed!!"<<std::endl;  
  28.     }  
  29.     //加载失败  
  30.     else  
  31.         std::cout << "DLL is not loaded!"<<std::endl;  
  32.     return a.exec();  
  33. }   

2、采用显式链接,调用C++类中的类对象、成员函数  【需要TestDLL.dll、TestDll.h

      如果你想导出并显式链接一组C++类中的成员函数又该怎么办呢?

这里有两个问题。

第一是C++成员函数名是经过修饰的(即使指定extern "C"标记也是这样);

第二是C++不允许将指向成员函数的指针转换成其它类型。这两个问题限制了C++类的显式链接。

下面介绍两种方法来解决这个问题:

①用虚函数表的方法,这也是COM使用的方法,利用Qt的QLibrary技术调用;

②用GetProcAddress直接调用。

用Qt的QPluginLoader类直接调用生成的DLL插件类对象

     

①虚函数表的方法,QLibrary 技术调用

TestDll.h代码

 

Cpp代码  收藏代码
  1. #ifndef TESTDLL_H  
  2. #define TESTDLL_H  
  3.   
  4. #include "testdll_global.h"  
  5.   
  6. class TESTDLL_EXPORT TestDll  
  7. {  
  8. public:  
  9.     TestDll();  
  10.     virtual~TestDll();    
  11.     virtual void helloWorld(); //类成员函数  
  12. private:  
  13.   
  14.   
  15. };     
  16. extern "C" TESTDLL_EXPORT TestDll* getTestDll(); //获取类TestDll的对象  
  17. #endif // TESTDLL_H  

 

 TestDll.cpp源码

 

Cpp代码  收藏代码
  1. #include <iostream>  
  2. #include "TestDll.h"  
  3.   
  4. TestDll::TestDll()  
  5. {  
  6.   
  7. }  
  8.   
  9. TestDll::~TestDll()  
  10. {  
  11.   
  12. }  
  13.   
  14. void TestDll::helloWorld()  
  15. {  
  16.     std::cout << "hello,world!";  
  17. }  
  18.   
  19. TestDll* getTestDll()  
  20. {  
  21.     return new TestDll();  
  22. }  

 

 TestMain项目中的main.cpp源码

 

Cpp代码  收藏代码
  1. #include <QtCore/QCoreApplication>  
  2. #include <iostream>  
  3. #include <QLibrary>  
  4. #include "../TestDll/TestDll.h"  //头文件还是需要加的,否则无法解析TestDll类  
  5. typedef TestDll* (*GetTestDll)();//定义函数指针,获取类TestDLL对象;    
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QCoreApplication a(argc, argv);  
  9.   
  10.     QLibrary mylib("TestDll.dll");   //声明所用到的dll文件  
  11.     int result;  
  12.     //判断是否正确加载  
  13.     if (mylib.load())                
  14.         {  
  15.             GetTestDll getTestDll = (GetTestDll)mylib.resolve("getTestDll");  
  16.             if(getTestDll)  
  17.             {  
  18.                 TestDll *testDll = getTestDll();  
  19.                 testDll->helloWorld();  
  20.                 delete testDll;  
  21.             }  
  22.     }  
  23.     //加载失败  
  24.     else  
  25.         std::cout << "DLL is not loaded!"<<std::endl;  
  26.     return a.exec();  
  27. }  

        这个方法的使用得用户可以很容易地为你的程序制作插件。它的缺点是创建对象的内存必须在dll中分配

 

 

②用GetProcAddress直接调用类对象中的成员函数

这个方法,我没测试,对我没对大作用,还得用def导出DLL函数,有兴趣的就参考一下这篇文章。DLL中类的显式链接

        ③用Qt的QPluginLoader类直接调用生成的DLL插件类对象

           这个方法,我单独写一篇总结,请看QPluginLoader的简单小例子VS2008+Qt 使用QPluginLoader访问DLL

 

3、采用隐式链接方法,通过QLibrary类对DLL中类对象、全局函数的调用  【需要TestDll.h、TestDll.cpp、TestDll.dll

 

TestDll.h

 

Cpp代码  收藏代码
  1. #ifndef TESTDLL_H  
  2. #define TESTDLL_H  
  3.   
  4. #include "testdll_global.h"  
  5.   
  6. class TESTDLL_EXPORT TestDll  
  7. {  
  8. public:  
  9.     TestDll();  
  10.     ~TestDll();   
  11.     void helloWorld(); //类成员函数  
  12. private:  
  13.   
  14.   
  15. };     
  16. extern "C" TESTDLL_EXPORT int add(int a,int b);  //自定义的外部函数  
  17. #endif // TESTDLL_H  

TestDll.cpp源码

Cpp代码  收藏代码
  1. #include <iostream>  
  2. #include "TestDll.h"  
  3.   
  4. TestDll::TestDll()  
  5. {  
  6.   
  7. }  
  8.   
  9. TestDll::~TestDll()  
  10. {  
  11.   
  12. }  
  13.   
  14. void TestDll::helloWorld()  
  15. {  
  16.     std::cout << "hello,world!";  
  17. }  
  18. int add(int a,int b)  
  19. {  
  20.     return a + b;  
  21. }  

 

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源码

Cpp代码  收藏代码
  1. #include <QtCore/QCoreApplication>  
  2. #include <iostream>  
  3. #include <QLibrary>  
  4. #include "../TestDll/TestDll.h"  
  5. //引入TestDll.lib文件,和上面的2,3步工作同理  
  6. //#pragma comment(lib, "../Debug/TestDll.lib")  
  7. int main(int argc, char *argv[])  
  8. {  
  9.     QCoreApplication a(argc, argv);  
  10.     int result = add(5,6);  
  11.     std::cout << result;  
  12.     TestDll dll;  
  13.     dll.helloWorld();  
  14.         return a.exec();  
  15. }  

 结果即可编译成功

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/458522.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unable to install pirate

真机测试的时候&#xff0c;报这个错误&#xff0c;主要原因就是证书的问题 xcode7以上进行的真机测试&#xff0c;可以没有使用证书&#xff0c;xcode可以进行的傻瓜操作帮助我们完成真机测试&#xff0c;但是今天我进行真机测试的时候报这个错误&#xff0c;同时xcode也不进…

memmove 对同一个指针不操作

memmove 对同一个指针不操作&#xff0c;所以调用memmove之前不用比较两个指针是否相同 void CTestDLLDlg::OnBnClickedButton6() {const int size 999999;char* data new char[size];memset(data, 1, size - 1);char* data1 new char[size];memset(data1, a, size - 1);clo…

Hadoop HDFS概念学习系列之HDFS升级和回滚机制(十二)

不多说&#xff0c;直接上干货&#xff01; HDFS升级和回滚机制 作为一个大型的分布式系统&#xff0c;Hadoop内部实现了一套升级机制&#xff0c;当在一个集群上升级Hadoop时&#xff0c;像其他的软件升级一样&#xff0c;可能会有新的bug或一些会影响现有应用的非兼容性变更出…

属性动画基础之ValueAnimator

概述 属性动画是谷歌在android3.0&#xff08;API level 11&#xff09;时候给我们带来了属性动画&#xff0c;真正意义上带来了”动画“&#xff0c;以前的帧动画也就4中效果的组合&#xff08;旋转、淡入淡出、放大缩小、平移&#xff09;&#xff0c;而且只是表面的动画&…

#Pragma Pack(n)与内存分配 pragma pack(push,1)与#pragma pack(1)的区别

from&#xff1a;http://blog.csdn.net/mylinx/article/details/7007309 #pragma pack(n) 解释一&#xff1a; 每个特定平台上的编译器都有自己的默认“对齐系数”(也叫对齐模数)。程序员可以通过预编译命令#pragma pack(n)&#xff0c;n1,2,4,8,16来改变这一系数&#xff0c;…

ShowDoc的搭建

其实&#xff0c;官方文档也说的很清楚了。主要贴一下我遇见的问题。环境&#xff1a;LNMP&#xff08;LAMP没试过&#xff0c;有兴趣的同学可以试试&#xff0c;然后发出来&#xff09;PHP5.3以上版本、php-mbstring模块、php-pdo模块、mysql数据库克隆或者下载代码&#xff1…

BroadcastReceiver

本文介绍Broadcast Receiver&#xff0c;包括几部分内容&#xff1a;Broadcast Receiver概述及实例、自定义Broadcast Receiver、Broadcast Receiver的实现细节、生命周期等。 csdn貌似今天出问题了&#xff0c;无法上传图片。 资料来源&#xff1a;最牛网&#xff0c;《官方解…

MFC CPropertySheet 多页面切换 实例

为了能实现在同一个页面实现多个页面的切换效果。CPropertySheet要与CPropertyPage一起使用。 首先 新建一个MFC工程--MFC AppWizard(exe), 取名Pagesheet, 选择Dialog based, 然后Finish. 2. 在对话框资源中插入两个对话框IDD_DIALOG1、IDD_DIALOG2&#xff0c;作为…

动画类的层次结构

CASpringAnimation类是CAABasicAnimation的子类 CAPropertyAnimation &#xff1a;是CAAnimation的子类&#xff0c;它支持动画地显示图层的keyPath&#xff0c;一般不直接使用。 iOS9.0之后新增CASpringAnimation类&#xff0c;它实现弹簧效果的动画&#xff0c;是CABasicAnim…

[原]小命令大作用:modprobe

调整网络为绑定模式&#xff0c;但启动时候会报错&#xff0c;此时执行命令 modprobe bonding 可以解决问题。 之前在磁盘方面遇到问题也是通过modprobe命令解决的&#xff0c;又遇到这个命令&#xff0c;似曾相识。于是看下该命令&#xff1a; Linux命令&#xff1a;modprobe …

setup2go制作安装程序

QT程序设计完毕时&#xff0c;我们就要发布自己的程序&#xff0c;发布程序有两种方法&#xff1a;一是静态编译&#xff0c;二是制作程序安装包。 静态编译好麻烦&#xff0c;我从来没有成功过&#xff0c;所以我用了动态编译方法&#xff0c;设计完成时&#xff0c;用release…

数据结构比较型排序算法分析及选择

比较型算法分为五类&#xff1a; 1、插入排序&#xff1a;直接插入排序、折半插入排序、希尔排序&#xff1b; 2、选择排序&#xff1a;直接选择排序、堆排序&#xff1b; 3、交换排序&#xff1a;快速排序、冒泡排序&#xff1b; 4、归并排序&#xff1b; 5、基数排序&#xf…

Frequent Pattern 挖掘之二(FP Growth算法)(转)

FP树构造 FP Growth算法利用了巧妙的数据结构&#xff0c;大大降低了Aproir挖掘算法的代价&#xff0c;他不需要不断得生成候选项目队列和不断得扫描整个数据库进行比对。为了达到这样的效果&#xff0c;它采用了一种简洁的数据结构&#xff0c;叫做frequent-pattern tree(频繁…

Sublime 解决目录显示为方块的问题

2019独角兽企业重金招聘Python工程师标准>>> 修改Perferences->Settings-User { "font_face": "Consolas Italic", #传说这个字体比较好看。 "font_size": 15, "ignored_packages": [ "Vintage" ], "dpi…

VS toolTip1控件的使用1

http://blog.csdn.net/Mr_Liyong/article/details/780141381、在工具栏找到“toolTip”控件后拖到窗体后&#xff0c;窗体下方会显示此控件则拖放成功。 2、单击此控件右键选择属性&#xff1a;开始 修改属性。 3、当添加一个TOOLTIP控件后&#xff0c;在WINFORM界面上所有的控…

【TL】【编码】瞬间移动-百度之星初赛(Astar Round2B)1003-2016.05.22

瞬间移动 Accepts: 1018 Submissions: 3620Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others) Problem Description有一个无限大的矩形&#xff0c;初始时你在左上角&#xff08;即第一行第一列&#xff09;&#xff0c;每次你都可以选择一个…

dom解析xml

为什么80%的码农都做不了架构师&#xff1f;>>> 转载自&#xff1a;http://www.cnblogs.com/shenliang123/archive/2012/05/11/2495252.html 使用eclipse需要手动导入crimson.jar包 org.w3c.dom(java dom)解析XML文档 位于org.w3c.dom操作XML会比较简单&#xff0c…

逃离北上广:你以为回到小城市就非常幸福了吗?

忘记在哪儿看的了。感觉不错&#xff0c;随手发出来。我博客也有更新&#xff0c;底下有留个人博客链接 在过去几年里。“逃离北上广”一直是一个热门短语。拿我自己来说&#xff0c;工作在上海&#xff0c;但又不是上海人。毕业后&#xff0c;就选择租房&#xff0c;首先就为这…

[WinForm] VS2010发布、打包安装程序(超全超详细)

from: http://blog.csdn.net/y13156556538/article/details/555321841、 在vs2010 选择“新建项目”→“ 其他项目类型”→“ Visual Studio Installer→“安装项目”&#xff1a; &#xff08;如果是在solution中添加&#xff0c;就直接solution -- 右键 -- 添加project&#…