2010年8月27日 星期五

[C++ 小學堂] 如何建立 export 的 dll 與如何動態呼叫 export 的 dll


前言 :
有關 dll (dynamic link library) 的介紹, 有興趣的可以參考 wiki : Dynamic-link library 的說明. 而它的存在主要是解決許多 常用 的函示被不同的應用程式使用時在記憶體都會占用一分空間造成浪費. 因此藉由 dll 讓所的的應用程式都參考到同一個記憶體位置以節省空間. 接著將介紹如何透過 MS Visual Studio 建立一個 dll 與動態呼叫該 dll export 的函式.

範例代碼 :
1. 步驟一 : 建立 DLL 專案(TestDll) :
首先來建立我們的 dll. 請在 VS 新建專案 > Win32 主控台應用程式 > 下一步 > 接著在應用程式類型選擇 "DLL" 與 其它選項選擇 "空專案" > 點擊完成.

2. 請建立下面代碼並進行編譯建立 Dll 文件 :
- Main.h 代碼 :
  1. extern "C" {  
  2. __declspec(dllexport) double AddNumbers(double a, double b);  
  3. }  

- Main.cpp 代碼 :
  1. #include   
  2. #include "Main.h"  
  3.   
  4. __declspec(dllexport) double AddNumbers(double a, double b) {return a+b;}  

3. 最後會建立 TestDll.dll, 接著再建立一個新的專案(DllLoader), 並建立以下代碼 :
- Main.cpp 代碼 :
  1. #include "Main.h"  
  2. #include   
  3. #include   
  4.   
  5. // DLL function signature  
  6. typedef double (*importFunction)(double, double);  
  7.   
  8. int main() {  
  9.     importFunction addNumbers;  
  10.     double result;  
  11.   
  12.     // Load DLL file  
  13.     HINSTANCE hinstLib = LoadLibrary(TEXT("TestDll.dll"));  
  14.     if (hinstLib == NULL) {  
  15.         printf("ERROR: unable to load DLL\n");  
  16.         system("pause");  
  17.         return 1;  
  18.     }  
  19.   
  20.     // Get function pointer  
  21.     addNumbers = (importFunction)GetProcAddress(hinstLib, "AddNumbers");  
  22.     if (addNumbers == NULL) {  
  23.         printf("ERROR: unable to find DLL function\n");  
  24.         FreeLibrary(hinstLib);  
  25.         system("pause");  
  26.         return 1;  
  27.     }  
  28.   
  29.     result = addNumbers(10, 20);  
  30.     printf("The result is %f\n", result);  
  31.   
  32.     // Unload DLL file  
  33.     FreeLibrary(hinstLib);  
  34.     system("pause");  
  35.     return 0;  
  36. }  

4. 執行後可以得到結果 :
The result is 30.000000

補充說明 :
* MSDN > LoadLibrary Function :
Loads the specified module into the address space of the calling process. The specified module may cause other modules to be loaded.
For additional load options, use the LoadLibraryEx function.

* MSDN > GetProcAddress Function :
Retrieves the address of an exported function or variable from the specified dynamic-link library (DLL).

* 使用 __declspec(dllexport) 從 DLL 匯出 :
在新版本的編譯器中,您可以使用 __declspec(dllexport) 關鍵字匯出 DLL 的資料、函式、類別或類別成員函式。__declspec(dllexport) 會將匯出指示詞加入至物件檔,這樣您就不需用到 .def 檔
在建置 DLL 時,您通常會建立標頭檔 (Header File),包含要匯出之函式的原型和/或類別,並在標頭檔的宣告中加入 __declspec(dllexport)。若要使程式更容易讀取,請為 __declspec(dllexport) 定義巨集,並在每個輸出的符號使用巨集 :
  1. #define DllExport   __declspec( dllexport )  

* 動態連結函式庫(Dynamic Linking Libraries,DLLs)介紹 :
使用該DLL裡面的函式可分為兩大類 :
1 、 隱式連結(Implicitly Link)
優點 :
1 、 靜態載入方式所使用到的這個DLL會在應用程式執行時載入, 然後就可以呼叫出所有由DLL中匯出的函式. 就好像是包含在程式中一般。
2 、 動作較為簡單,載入的方法由編譯器負責處理,咱們不須動腦筋。
缺點 :
1 、 當這個程式靜態載入方式所使用到的這個DLL不存在時, 這個程式在開始時就出現無法找到DLL的訊息而 導致應用程式無執行。
2 、 編譯時需要加入額外的import library.
3 、 若是要載入的DLLs一多,載入應用程式的速度會便慢.
4 、 若遇到不同品牌的C++編譯器時, 靜態載入就沒有這麼簡單, 因為當函式經過Calling Conventions的處理後, 若要使用其他品牌編譯器的DLL須得大動干戈才行.

2 、 顯式連結(Explicit Linking)
優點 :
1 、DLL只要需要時才會載入到記憶體中, 可以更有效的使用記憶體.
2 、 應用程式載入的速度較使用隱式鏈結時快, 因為當程式開始載入時並不需要把DLL給載入到行程中。
3 、 編譯時不須額外的import library檔。
4 、 讓我們可以更清楚DLL的載入流程。
缺點 :
就是得要自行連結,自然要多點code囉!
This message was edited 8 times. Last update was at 27/08/2010 16:34:34

沒有留言:

張貼留言

[Git 常見問題] error: The following untracked working tree files would be overwritten by merge

  Source From  Here 方案1: // x -----删除忽略文件已经对 git 来说不识别的文件 // d -----删除未被添加到 git 的路径中的文件 // f -----强制运行 #   git clean -d -fx 方案2: 今天在服务器上  gi...