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…

.Net JIT

.Net JIT(转) JIT 转载于:https://www.cnblogs.com/HelloMyWorld/p/5501135.html

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

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

TCP协议的特性

TCP协议的特性&#xff1a;建立连接&#xff1a;三次握手将数据打包成段&#xff1a;校验和&#xff08;CRC32&#xff09;确认、重传及超时排序&#xff1a;逻辑序号流量控制&#xff1a;滑动窗口算法拥塞控制&#xff1a;慢启动和拥塞便面算法转载于:https://blog.51cto.com/…

属性动画基础之ValueAnimator

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

经验之谈:10位顶级PHP大师的开发原则

导读&#xff1a;在Web开发世界里&#xff0c;PHP是最流行的语言之一&#xff0c;从PHP里&#xff0c;你能够很容易的找到你所需的脚本&#xff0c;遗憾的是&#xff0c;很少人会去用“最佳做法”去写一个PHP程序。这里&#xff0c;我们向大家介绍PHP的10种最佳实践&#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;《官方解…

如何确定VS编译器版本--_MSC_VER || #if _MSC_VER 1000 #pragma once #endif

如何确定VS编译器版本 _MSC_VER是MSVC编译器的内置宏&#xff0c;定义了编译器的版本&#xff0c;_MSC_VER 值对应版本关系 MSVC 11.0 _MSC_VER 1700 (Visual Studio 2012) MSVC 10.0 _MSC_VER 1600 (Visual Studio 2010) MSVC 9.0 _MSC_VER 1500 (Visual Studio 2008) …

NIO复习02

Selector 1. Selector&#xff08;选择器&#xff09;是Java NIO中能够检测一到多个NIO通道&#xff0c;并能够知晓通道是否为诸如读写事件做好准备的组件。这样&#xff0c;一个单独的线程可以管理多个channel&#xff0c;从而管理多个网络连接。 2. Selector的创建&#xff1…

c/c++标准预定义宏

C标准中的一些预定义宏昨天写代码时需要在代码获取当前编译时间&#xff0c;从而可动态地作为版本信息&#xff0c;因此用到了C标准中的一些预定义的宏。在此将C标准中定义的几个宏一并总结一下&#xff1a; __DATE__ 进行预处理的日期&#xff08;“Mmm dd yyyy”形式的字符串…

安装cocoa pods时出现Operation not permitted - /usr/bin/xcodeproj的问题

在更新完ruby&#xff0c;更换Ruby镜像&#xff0d;&#xff0d;淘宝的那个镜像(https://ruby.taobao.org/ )已经不可用了。官方的需要FQ。所以我们现在用最新支持的ruby镜像(https://gems.ruby-china.org/) 安装cocoa pods时&#xff0c; 在命令行中输入&#xff1a; 安装&…

js 日期控件laydate使用

官网 http://sentsin.com/layui/laydate/ 1. 下载官网上的压缩包,解压后只需要复制laydate 文件夹到你的项目中; 2. 在页面引入 <script type"text/javascript" src"js/laydate/laydate.js"></script> 3. 在页面添加: <div class"i…

老李推荐:第8章2节《MonkeyRunner源码剖析》MonkeyRunner启动运行过程-解析处理命令行参数 2...

我们这一节会先去分析下monkeyrunner是如何对参数进行处理的&#xff0c;我们跳转到MonkeyRunnerOptions这个类里面的processOptions这个方法&#xff1a; 93 public static MonkeyRunnerOptions processOptions(String[] args) 94 { 95 int index 0; 96 97 Strin…

MFC CPropertySheet 多页面切换 实例

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