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.pswp.cn/news/458522.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458522.shtml
英文地址,請注明出處:http://en.pswp.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;作為…