将自己的类封装为lib的方法
前言:
Windows API中所有的函數都包含在dll中,其中有3個最重要的DLL。
(1)???Kernel32.dll 它包含那些用于管理內存、進程和線程的函數,例如CreateThread函數;
(2)???User32.dll ? 它包含那些用于執行用戶界面任務(如窗口的創建和消息的傳送)的函數,例如CreateWindow函數;
(3)???GDI32.dll ?? 它包含那些用于畫圖和顯示文本的函數。
靜態庫和動態庫
(1)???靜態庫
?????????函數和數據被編譯進一個二進制文件(通常擴展名為.LIB)。在使用靜態庫的情況下,在編譯鏈接可執行文件時,鏈接器從庫中復制這些函數和數據并把它們和應用程序的其他模塊組合起來創建最終的可執行文件(.Exe文件).當發布產品時,只需要發布這個可執行文件,并不需要發布被使用的靜態庫。
(2)???動態庫
??????在使用動態庫的時候,往往提供兩個文件:一個引入庫(.lib)文件和一個DLL(.dll)文件。雖然引入庫的后綴名也是”lib”,但是動態庫的引入庫文件和靜態庫文件有著本質上的區別,對一個DLL來說,其引入庫文件(.lib)包含該DLL導出的函數和變量的符號名,而.dll文件包含該DLL實際的函數和數據。在使用動態庫的情況下,在編譯鏈接可執行文件時,只需要鏈接該DLL的引入庫文件,該DLL中的函數代碼和數據并不復制到可執行文件中,直到可執行程序運行時,才去加載所需的DLL,將該DLL映射到進程的地址空間外,然后訪問DLL中導出的函數。這時,發布產品時,除了發布可執行文件以外,同時還要發布該程序將要調用的動態鏈接庫。
一、DLL的創建?
(1):方法引自于此文: http://blog.csdn.net/wqvbjhc/article/details/6029168?
????????????? 對于圖像缺失問題,請訪問原文鏈接.
(2):創建DLL 此文解釋已經相當詳細,地址:http://hi.baidu.com/lipeiyi2006/item/df1d035734472d9509be17c0
? 不過為了防止以后博主刪除,還是copy一遍....、
創建項目:?Win32->Win32項目,名稱:MyDLL
選擇DLL?( D)?->完成.
1、新建頭文件testdll.h
testdll.h代碼如下:
Ps:__declspec(dllexport)的作用,它就是為了省掉在DEF文件中手工定義導出哪些函數的一個方法。當然,如果你的DLL里全是C++的類的話,你無法在DEF里指定導出的函數,只能用__declspec(dllexport)導出類。
*注:extern?"C"是可選的,extern?"C"是為了保證導出的DLL函數名不發生變化。如果寫了extern?"C",那么導出和導入都要寫,要保證一致。
?????????如果要導出的是類,不能在類名前加extern?"C",切記切記!!編譯不會通過的。
如果在新建dll的時候選擇空白的文件(即不用vs自帶的幫你生成)的話,注意一定要自己手動添加def文件。否則生成不了lib文件。
2、新建源文件testdll.cpp
3、新建模塊定義文件mydll.def
mydll.def代碼如下:LIBRARY "MyDLL"EXPORTSAdd @1
PS:這個在VS2012中可能沒有,所以要這樣操作:
方法是:在所建工程上單擊鼠標右鍵,在彈出的右鍵菜單中選擇“添加-->新建項....---->模塊定義文件”,在該模塊定義文件中寫導出函數表,單擊確定
Vs2012默認生成dll,但不生成Lib文件。這個.def文件可以生成lib文件。
4、vs2010自動創建dllmain.cpp文件,它定義了DLL?應用程序的入口點。
dllmain.cpp代碼如下:
//?dllmain.cpp?:?定義?DLL?應用程序的入口點。
最后,編譯生成MyDLL.dll文件和MyDLL.lib文件。
1>------ 已啟動生成: 項目: MyDLL, 配置: Debug Win32 ------ 1> dllmain.cpp ========== 生成: 成功 1 個,失敗 0 個,最新 0 個,跳過 0 個 ========== 1>------ 已啟動生成: 項目: MyDLL, 配置: Debug Win32 ------ 1> stdafx.cpp 1> testdll.cpp 1> MyDLL.cpp 1> 正在生成代碼... 1> 正在創建庫 D:\Visual C++\工程\Libaray\MyDLL\Debug\MyDLL.lib 和對象 D:\Visual C++\工程\Libaray\MyDLL\Debug Ps:errorc2061 語法錯誤 標識符錯誤原因:是因為頭文件的順序不對。
解決方法:調整頭文件的順序。
轉自:http://liuyunfeng484.blog.163.com/blog/static/66831715201232810449824/
二、DLL的使用(靜態鏈接、隱式鏈接)
如何在C++中調用DLL中的函數
應用程序使用DLL可以采用兩種方式:一種是隱式鏈接,另一種是顯式鏈接。在使用DLL之前首先要知道DLL中函數的結構信息。Visual C++6.0在VC\bin目錄下提供了一個名為Dumpbin.exe的小程序,用它可以查看DLL文件中的函數結構。另外,Windows系統將遵循下面的搜索順序來定位DLL: 1.包含EXE文件的目錄,2.進程的當前工作目錄, 3.Windows系統目錄, 4.Windows目錄,5.列在Path環境變量中的一系列目錄。
1.隱式鏈接
隱式鏈接就是在程序開始執行時就將DLL文件加載到應用程序當中。實現隱式鏈接很容易,只要將導入函數關鍵字_declspec(dllimport)函數名等寫到應用程序相應的頭文件中就可以了。下面的例子通過隱式鏈接調用MyDll.dll庫中的Min函數。首先生成一個項目為TestDll,在DllTest.h、DllTest.cpp文件中分別輸入如下代碼:
?
//Dlltest.h #pragma comment(lib,"MyDll.lib") extern"C"_declspec(dllimport) int Max(int a,int b); extern"C"_declspec(dllimport) int Min(int a,int b);//TestDll.cpp #include #include"Dlltest.h" void main() {int a; a=min(8,10) printf("比較的結果為%d\n",a);}在創建DllTest.exe文件之前,要先將MyDll.dll和MyDll.lib拷貝到當前工程所在的目錄下面,也可以拷貝到windows的System目錄下。如果DLL使用的是def文件,要刪除TestDll.h文件中關鍵字extern "C"。TestDll.h文件中的關鍵字Progam commit是要Visual C+的編譯器在link時,鏈接到MyDll.lib文件,當然,開發人員也可以不使用#pragma comment(lib,"MyDll.lib")語句,而直接在工程的Setting->Link頁的Object/Moduls欄填入MyDll.lib既可。
2.顯式鏈接
顯式鏈接是應用程序在執行過程中隨時可以加載DLL文件,也可以隨時卸載DLL文件,這是隱式鏈接所無法作到的,所以顯式鏈接具有更好的靈活性,對于解釋性語言更為合適。不過實現顯式鏈接要麻煩一些。在應用程序中用LoadLibrary或MFC提供的AfxLoadLibrary顯式的將自己所做的動態鏈接庫調進來,動態鏈接庫的文件名即是上述兩個函數的參數,此后再用GetProcAddress()獲取想要引入的函數。自此,你就可以象使用如同在應用程序自定義的函數一樣來調用此引入函數了。在應用程序退出之前,應該用FreeLibrary或MFC提供的AfxFreeLibrary釋放動態鏈接庫。下面是通過顯式鏈接調用DLL中的Max函數的例子。
?
#include #include void main(void) { typedef int(*pMax)(int a,int b); typedef int(*pMin)(int a,int b);HINSTANCE hDLL; PMax MaxHDLL=LoadLibrary("MyDll.dll");//加載動態鏈接庫MyDll.dll文件;Max=(pMax)GetProcAddress(hDLL,"Max"); A=Max(5,8);Printf("比較的結果為%d\n",a);FreeLibrary(hDLL);//卸載MyDll.dll文件; }在上例中使用類型定義關鍵字typedef,定義指向和DLL中相同的函數原型指針,然后通過LoadLibray()將DLL加載到當前的應用程序中并返回當前DLL文件的句柄,然后通過GetProcAddress()函數獲取導入到應用程序中的函數指針,函數調用完畢后,使用FreeLibrary()卸載DLL文件。在編譯程序之前,首先要將DLL文件拷貝到工程所在的目錄或Windows系統目錄下。
使用顯式鏈接應用程序編譯時不需要使用相應的Lib文件。另外,使用GetProcAddress()函數時,可以利用MAKEINTRESOURCE()函數直接使用DLL中函數出現的順序號,如將GetProcAddress(hDLL,"Min")改為GetProcAddress(hDLL, MAKEINTRESOURCE(2))(函數Min()在DLL中的順序號是2),這樣調用DLL中的函數速度很快,但是要記住函數的使用序號,否則會發生錯誤。
warning LNK4070:exp : warning LNK4070: .EXP中的 /OUT:A.dll指令與輸出文件名"../outdir/Debug/B.dll"不同;忽略指令
產生原因是:這個工程的def文件中LIBRARY字段的值和輸出文件不一樣造成的。
解決辦法:修改LIBRARY字段的值,使得和輸出文件保持一致。
轉自:http://blog.163.com/gost_008/blog/static/87202204200862932528217/
三:DLL的模塊定義文件(.DEF)??
動態連接庫函數或者成員的導出可以用
_declspec(dllexport)來實現,比如為了導出voidSayHello()函數,則在DLL文件中這么聲明(或者定義):
_declspec(dllexport)void SayHello();
也可以不用_declspec(dllexport),而采用.def文件來說明要導出的函數或成員:
.def文件的格式:
LIBRARYABC //ABC為.dll文件的名字,也就是dll工程的名字
EXPORTS
SayHello@1
這樣,就從ABC.dll文件中導出了SayHello這個函數,
后面的那個"@1"的含義為:
從動態連接庫文件中導出的函數或者成員可以用名字來標識,也可以用序號來表示,一般情況下用名字來標識,序號由系統來設置,但是也可以用"@1"的格式來自己定義,表示SayHello函數的序號為1
不想使用__declspec(dllexport)而單獨使用.def文件導出類,不知道如何實現?1,把你要從dll輸出的每個類,都設計一個基類,這是個純虛,即所有函數都是“virtual...=0;”的。把這些寫成一個.h;???
? ??? 2,把dll里的類都從相應的基類派生,并實現每一個純虛函數。并給dll設計一個可動態導出的函數,這個函數里???return??? new??? CxxxInDll; ??
? ??? 3,在調用dll的程序里定義純虛基類的指針,并賦予第二步返回的值。? ?
???現在可以動態加載、調用dll里的類了??纯?/span>COM原理,你就有啟發了。熟練了后會發現這個方法在小型應用里非常有效!(在大型應用里,由于缺乏生存期控制,所以不安全)? ?
? ????需要補充的是:需要為每個類增加定義一個Release函數,函數里delete???this,不要在調用dll的程序里直接delete從第二步獲得的指針。
四:我的方法
?對于Vs建立DLL文件的方法過程為:
(1):建立一個空工程,命名
(2):把工程生成文件設置為DLL
(3):添加現有項目,把類里面對外展示的Public成員函數,在頭文件函數聲明前面添加_declspec(dllexport)
(4):切記:要把構造函數和析構函數前面也加上_declspec(dllexport)
(5):生成dll文件,在工程的Release或者Debug文件夾里面會生成DLL和LIb文件,然后整個項目.h文件,DLL和LIb文件 為最后需要的文件
總結
以上是生活随笔為你收集整理的将自己的类封装为lib的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 现在小黄车还能退押金吗
- 下一篇: vs2012下 error4996