一、VS2013動態庫文件的創建
1、新建項目,win32,win32項目,輸入項目名稱,例如MakeDll。
2、”確定“——”下一步“,選擇”DLL“選項,再點”完成“:
3、菜單欄選擇”項目“——>”添加新項“,來創建頭文件MakeDll.h。
在MakeDll.h中輸入以下例子代碼:
1 #ifdef DLL_API//如果已經定義就什么都不做 2 //nothing to do 3 #else //否則定義DLL_API 4 #define DLL_API __declspec(dllexport) //_declspec(dllexport):導出標志 5 #endif 6 #include <iostream> 7 using namespace std; 8 DLL_API int add(int a, int b);//導出單獨的函數 9 class DLL_API Point //導出類,其自身所有函數都將被導出,可單獨對某些類函數導出 10 { 11 private: 12 float x, y; 13 public: 14 Point(); 15 void SetPoint(float a, float b); 16 void DisPlay(); 17 };
4、創建cpp文件:MakeDll.cpp。
在MakeDll.cpp中輸入以下例子代碼:
1 #include "MakeDll.h" 2 3 int add(int a, int b) 4 { 5 return a + b; 6 } 7 8 Point::Point() 9 { 10 x = 0.0f; 11 y = 0.0f; 12 } 13 14 void Point::SetPoint(float a, float b) 15 { 16 x = a; 17 y = b; 18 } 19 void Point::DisPlay() 20 { 21 cout << "x=" << x << endl; 22 cout << "y=" << y << endl; 23 }
5、菜單欄選擇”生成——>生成解決方案“。
此時在MakeDll項目所在目錄下的Debug目錄下的文件有MakeDll.dll和MakeDll.lib了。生成動態鏈接庫文件OK。
二、使用剛才創建的動態庫
1、新建項目——win32控制台應用程序,命名為UseDll,並創建一個lib文件,將MakeDll.lib引導庫放進去,
並將MakeDll.dll放進debug下,編譯器會自動搜素到這個文件,當然可以放在系統目錄下。
2、告訴編譯器頭文件MakeDll.h的位置(見包含目錄)、引導庫位置(見庫目錄)及其名字(見附加依賴項)。注意,以下是添加后的顯示結果。
圖.包含目錄的設置
圖.庫目錄的設置
圖.附加依賴項的設置
3、最后,動態庫的測試程序如下,測試程序需要引用頭文件:
1 #include <iostream> 2 #include "MakeDll.h" 3 using namespace std; 4 5 int main() 6 { 7 int a = 10; 8 int b = 2; 9 int c = add(a, b); 10 cout << c << endl; 11 Point p1, p2; 12 p2.SetPoint(5.6f, 7.8f); 13 p1.DisPlay(); 14 p2.DisPlay(); 15 getchar(); 16 return 0; 17 }
運行結果:
至此測試成功!
三、h頭文件 .lib庫文件 .dll動態鏈接庫文件關系
.h頭文件是編譯時必須的,lib是鏈接時需要的,dll是運行時需要的。
附加依賴項添加的是.lib而不是.dll,若生成了DLL,則肯定也生成了LIB文件。
.h .lib .dll三者的關系:
H文件的作用:聲明函數接口
DLL文件作用:函數可執行代碼
LIB文件作用:當我們在自己的程序中引用了一個H文件里的函數,鏈接器怎么知道該調用哪個DLL文件呢?這就是LIB文件的作用了。它告訴鏈接器調用的函數在哪個DLL中,函數執行代碼在DLL中的什么位置,這也就是為什么需要附加依賴項.LIB文件,它起到橋梁的作用。
如果是生成靜態庫文件,則沒有DLL,只有lib,這時函數可執行代碼部分也在lib文件中。
目前以lib后綴的庫有兩種,一種為靜態鏈接庫(Static Libary,以下簡稱“靜態庫”),另一種為動態連接庫(DLL,以下簡稱“動態庫”)的導入庫(Import Libary,以下簡稱“導入庫”)。靜態庫是一個或者多個obj文件的打包,所以有人干脆把從obj文件生成lib的過程稱為Archive,即合並到一起。比如你鏈接一個靜態庫,如果其中有錯,它會准確的找到是哪個obj有錯,即靜態lib只是殼子。動態庫一般會有對應的導入庫,方便程序靜態載入動態鏈接庫,否則你可能就需要自己LoadLibary調入DLL文件,然后再手工GetProcAddress獲得對應函數了。有了導入庫,你只需要鏈接導入庫后按照頭文件函數接口的聲明調用函數就可以了。導入庫和靜態庫的區別很大,他們實質是不一樣的東西。靜態庫本身就包含了實際執行代碼、符號表等等,而對於導入庫而言,其實際的執行代碼位於動態庫中,導入庫只包含了地址符號表等,確保程序找到對應函數的一些基本地址信息。
一般的動態庫程序有lib文件和dll文件。lib文件是必須在編譯期就連接到應用程序中的,而dll文件是運行期才會被調用的。如果有dll文件,那么對應的lib文件一般是一些索引信息,具體的實現在dll文件中。如果只有lib文件,那么這個lib文件是靜態編譯出來的,索引和實現都在其中。
靜態編譯的lib文件的好處:給用戶安裝時就不需要再掛動態庫了。但也有缺點,就是導致應用程序比較大,而且失去了動態庫的靈活性,在版本升級時,同時要發布新的應用程序才行。
在動態庫的情況下,有兩個文件,而一個是引入庫(.LIB)文件,一個是DLL文件,引入庫文件包含被DLL導出的函數的名稱和位置,DLL包含實際的函數和數據,應用程序使用LIB文件鏈接到所需要使用的DLL文件,庫中的函數和數據並不復制到可執行文件中,因此在應用程序的可執行文件中,存放的不是被調用的函數代碼,而是DLL中所要調用的函數的內存地址,這樣當一個或多個應用程序運行是再把程序代碼和被調用的函數代碼鏈接起來,從而節省了內存資源。從上面的說明可以看出,DLL和.LIB文件必須隨應用程序一起發行,否則應用程序將會產生錯誤。
在VC中加載LIB文件的幾種方法:
①LIB文件直接加入到工程文件列表中
在VC中打開File View一頁,選中工程名,單擊鼠標右鍵,然后選中"Add Files to Project"菜單,在彈出的文件對話框中選中要加入DLL的LIB文件即可。
②設置工程的 Project Settings來加載DLL的LIB文件
之前的步驟提到過,這里不再提。
③通過程序代碼的方式
加入預編譯指令#pragma comment (lib,"*.lib"),這種方法優點是可以利用條件預編譯指令鏈接不同版本的LIB文件。因為,在Debug方式下,產生的LIB文件是Debug版本,如Regd.lib;在Release方式下,產生的LIB文件是Release版本,如Regr.lib。
當應用程序對DLL的LIB文件加載后,還需要把DLL對應的頭文件(*.h)包含到其中,在這個頭文件中給出了DLL中定義的函數原型,然后聲明。
四、動態鏈接庫的優點
因為動態鏈接庫是將功能封裝在一起的模塊,因此,與將代碼直接寫入調用模塊中相比,它不僅可以提高程序的復用,減少代碼開發工作量,同時使得功能更新更方便。除了這些模塊化帶來的優點外,動態鏈接庫的工作方式也決定了它先天具有比靜態鏈接更多的優點,如下所述。
1、節約內存和減少交換:當應用程序使用動態鏈接時,多個進程可以同步使用一個DLL共享內存中DLL的單個副本。相比之下,當應用程序使用靜態鏈接庫時,Windows必須為每個應用程序裝載一個庫代碼的副本到內存中。
2、節約磁盤空間:當應用程序使用動態鏈接時,多個應用程序可以共享磁盤上單個DLL副本。相比之下,當應用程序使用靜態鏈接庫時,每個應用程序要將庫代碼作為獨立的副本鏈接到可執行鏡像中。
3、當DLL中的函數修改時,只要函數參數、調用規定和返回值沒有改變,使用DLL的應用程序不需要重新編譯或鏈接。而靜態鏈接的函數改變時,需要應用程序重新鏈接。
4、支持多語言編程:只要應用程序遵循相同的調用規范,則使用不同編程語言編寫的程序可以調用相同的DLL函數。程序和DLL函數必須兼容:函數定義的參數入棧順序,函數或應用程序誰來負責清理堆棧,參數是否傳入寄存器中等方面必須兼容。
5、輕松的創建中間版本:通過將資源放入DLL中,使得創建應用程序的中間版本非常簡單。如可以將應用程序的每個語言版本的字符串放到單獨的一個資源DLL中,並為不同的語言版本裝載合適的資源DLL就可以了。
雖然使用DLL有諸多的優點,但是也需要格外注意使用DLL的缺點。即調用DLL的應用程序不是獨立的,程序的運行依賴於所使用的DLL是否存在。