先讲一下对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 文件源代码一直不变

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

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

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

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

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

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

2、采用显示链接,调用C++类中的类对象、成员函数 

如果你想导出并显式链接一组C++类中的成员函数又该怎么办呢?这里有两个问题。第一是C++成员函数名是经过修饰的(即使指定extern "C"标记也是这样);第二是C++不允许将指向成员函数的指针转换成其它类型。这两个问题限制了C++类的显式链接。下面介绍两种方法来解决这个问题:

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

②用GetProcAddress直接调用。

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

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

TestDll.h代码

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

TestDll.cpp源码

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

TestMain项目中的main.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. QLibrary mylib("TestDll.dll");   //声明所用到的dll文件
  10. int result;
  11. //判断是否正确加载
  12. if (mylib.load())
  13. {
  14. GetTestDll getTestDll = (GetTestDll)mylib.resolve("getTestDll");
  15. if(getTestDll)
  16. {
  17. TestDll *testDll = getTestDll();
  18. testDll->helloWorld();
  19. delete testDll;
  20. }
  21. }
  22. //加载失败
  23. else
  24. std::cout << "DLL is not loaded!"<<std::endl;
  25. return a.exec();
  26. }

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

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

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

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

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

3、采用隐式链接方法,通过QLibrary类对DLL中类对象、全局函数的调用

TestDll.h

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

TestDll.cpp源码

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

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

  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. }

结果即可编译成功

==========================DLL常识=============================
为隐式链接到 DLL,可执行文件必须从 DLL 的提供程序获取下列各项:

包含导出函数和/或 C++ 类的声明的头文件(.H 文件)
要链接的导入库(.LIB files)。(生成 DLL 时链接器创建导入库。)
实际的 DLL(.DLL 文件)

隐 式链接需要一个由动态连接库产生的.LIB文件(导入库),并把它链接到应用程序的工程中.该导入库仅包含加载DLL的代码和实现DLL函数调用的代码。 在导入库中找到外部函数后,会通知链接器此函数的代码在DLL中。要解析对DLL的外部引用,链接器只需向可执行文件中添加信息,通知系统在进程启动时应 在何处查找 DLL 代码。

系统启动包含动态链接引用的程序时,它使用程序的可执行文件中的信息定位所需的DLL。如果系统无法定位 DLL,它将终止进程并显示一个对话框来报告错误。如果找到了DLL,系统将DLL模块映射到进程的地址空间中。与程序代码的其余部分一样,DLL代码在 进程启动时映射到进程的地址空间中,且仅当需要时才加载到内存中。

Windows将遵循下面的搜索顺序来定位DLL

包含EXE文件的目录
进程的当前工作目录
Windows系统目录(system/system32)。GetSystemDirectory 函数检索此目录的路径。
Windows目录.GetWindowsDirectory 函数检索此目录的路径。
列在Path环境变量中的一系列目录

转自:http://qimo601.iteye.com/blog/1397936

Qt Dll总结(二)——创建及使用Qt的Dll(转载)的更多相关文章

  1. Qt Lighthouse学习(二),就是QPA(Qt Platform Abstraction) 项目的名字

    上一次关注Qt Lighthouse是在6月初,可是现在都8月底了.时间真快... Lighthouse 是 QPA(Qt Platform Abstraction) 项目的名字,它使得将Qt移植到新 ...

  2. Qt DLL总结【二】-创建及调用QT的 DLL(三篇)good

    目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...

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

    开发环境:VS2008+Qt4.7.4 最近看了不少Qt的DLL例子,总结一下如何创建和调用QT 动态链接库. 先讲一下对QT动态链接库的调用方法,主要包括: 1.显式链接DLL,调用DLL的全局函数 ...

  4. qt 创建及调用QT的 DLL

    先讲一下对QT动态链接库的调用方法,主要包括: 1.显式链接DLL,调用DLL的全局函数,采用Qt的QLibrary方法 2.显示链接DLL,调用DLL中类对象.成员函数.(通过对象即可实现类成员函数 ...

  5. Linux Qt动态库的创建和使用

    一.创建动态库 编写一个共享库类,比如: //..base.h class Base : public QObject { Q_OBJECT public: ); void PrintLog(QStr ...

  6. Qt DLL总结【三】-VS2008+Qt 使用QPluginLoader访问DLL

    目录 Qt DLL总结[一]-链接库预备知识 Qt DLL总结[二]-创建及调用QT的 DLL Qt DLL总结[三]-VS2008+Qt 使用QPluginLoader访问DLL 开发环境:VS20 ...

  7. Qt技巧:Win7下打包发布Qt程序(解释的比较清楚,把exe和dll伪装合并成一个文件)

    转自:http://www.stardrad.com/blog/qt-5%E7%A8%8B%E5%BA%8F%E5%9C%A8windows%E4%B8%8A%E7%9A%84%E5%8F%91%E5 ...

  8. Qt编译mysql以及创建表后进行导入操作

    鉴于很多同学对Qt编译myql总是不能成功.出现各种问题,今天特此写出本教程,希望可以帮到须要的同学.        首先,须要明确编译的目的和原理. 目的:Qt 5.2版本号曾经都是不带mysql驱 ...

  9. PyQt(Python+Qt)学习随笔:Qt Designer中Action创建的方法

    在Qt Designer中,可以两种方法创建Action对象,一种是菜单定义时,一种是单独定义. 一.定义菜单创建Action 在Qt Designer中创建菜单时,如果对应菜单是最终执行的菜单项,则 ...

随机推荐

  1. PHPstorm破解方法及xdebug的断点调试

    原文地址:http://www.php.cn/php-weizijiaocheng-381903.html 相信用PHPstorm的程序员肯定很多,令人头疼的是下载的PHPstorm是有使用期限的,小 ...

  2. mosquitto SSL认证

    [11]MQTT mosquitto 双向SSL认证配置方式 [12]MQTT mosquitto 单向SSL认证的配置方式 Mosquitto服务器的搭建以及SSL/TLS安全通信配置(比较可信) ...

  3. pro*c的使用

    一.什么是Pro*c程序 在oracle数据库管理系统中,有三种访问数据库的方法:       1.用 SQL*Plus,直接输入sql命令以命令行交换的方式访问数据库       2.用一些应用开发 ...

  4. 【LeetCode每天一题】Pascal's Triangle(杨辉三角)

    Given a non-negative integer numRows, generate the first numRows of Pascal's triangle. In Pascal's t ...

  5. 要求根据RandomStr.java:使用类型转换生成六位验证字符串,示例程序每次运 行时,都会生成不同的字符串。

    1.程序设计思想验证码 ①定义一个字符串变量来保存随机生成的. ②利用循环产生六位随机数,在产生每一位时将其转换为char类型并写在字符串后面. ③利用对话框显示生成的验证码,并提示用户输入验证码. ...

  6. Servlet交互与JSP

    主要内容介绍 数据共享与页面跳转 1. 为什么要有跳转: Servlet需要跳转到其它Servlet中,因为我们需要职责分明,不同Servlet来完成不同的功能 Servlet跳转到JSP中,Serv ...

  7. 定位amdu无法使用的根因并解决

    环境: OEL 5.7 + Oracle 10g + amdu_X86-64 现象: 我的两套实验环境,一套单实例,一套RAC,操作系统都是OEL 5.7,数据库都是Oracle 10g,上传同样的a ...

  8. 17.在自适应屏幕里通过JQ来获取宽高并赋给需要的

    在自适应屏幕里通过JQ来获取宽高并赋给需要的div. var height = document.documentElement.clientHeight; $(window).height();(同 ...

  9. linux df查看硬盘使用量 du查看文件所占大小

    df 常用来查看磁盘的占用情况. du 常用来查看文件夹的大小等. Linux命令: df  [-ahikHTm]  [目录或者文件夹] 参数: -h : 以交较易识别的方式展示使用量  111100 ...

  10. 加减plugin

    plugin插件↓↓ ;(function (underfined) { "use strict" var _global; //插件函数 /* var plugin = { ad ...