動態鏈結庫與靜態鏈結庫

2021-05-24 12:16:53 字數 3110 閱讀 7409

原貼出處: http://blog.csdn.net/benny5609/archive/2008/04/17/2298998.aspxs

還有參考: http://msdn.microsoft.com/zh-cn/library/1ez7dh12(v=vs.100).aspxs

首先通過乙個簡單的靜態鏈結庫的例子來了解庫的概念。

1. 新建乙個 win32專案 myfirstlib。

在"模板" 視窗中選擇 "win32控制台應用程式"

下一步在 "應用程式嚮導" 中選擇 "靜態庫", 並勾選 "空專案"

2. 新增lib.h 和 lib.cpp

3. 編譯該專案("生成" --> "生成解決方案"),就能得到我們需要的 .lib 檔案。 

下面只需要將 標頭檔案 和 .lib檔案 提供給應用程式,就可以使用lib中定義的add函式了。

4. 新建乙個win32控制台專案libcall, 新建乙個main.cpp檔案, 並將上面 h檔案 和 lib檔案複製到main.cpp所在目錄。

在具體進入各類dll的詳細闡述之前,有必要對庫檔案的除錯與檢視方法進行一下介紹,因為從下一節開始我們將面對大量的例子工程。

由於庫檔案不能單獨執行,因而在按下f5(開始debug模式執行)或ctrl+f5(執行)執行時,其彈出如下圖所示的對話方塊,要求使用者輸入可執行文 件的路徑來啟動庫函式的執行。這個時候我們輸入要呼叫該庫的exe檔案的路徑就可以對庫進行除錯了,其除錯技巧與一般應用工程的除錯一樣。

通常有比上述做法更好的除錯途徑,那就是將庫工程和應用工程(呼叫庫的工程)放置在同一vc工作區,只對應用工程進行除錯,在應用工程呼叫庫中函式的語 句處設定斷點,執行後按下f11,這樣就單步進入了庫中的函式。下一節中我們就將myfirstdll 跟 dllcall專案放在同一工作區(同一"解決方案")。如下圖所示:

1. 如第2節中一般,新建乙個動態鏈結庫專案。

新建win32專案myfistdll, 選擇win32控制台應用程式,在"應用程式嚮導"視窗中選擇 "dll", 並且選中"空專案"

2. 為該專案新增 lib.h 和 lib.cpp

3. 編譯生成dll檔案 和 lib檔案(這裡的lib並不是靜態庫,而只是包含了dll匯出函式的符號名及函式入口等資訊)

4. 新建乙個專案win32控制台應用程式 dllcall, 並且在 "解決方案"中選擇"添入該解決方案"。這會將該專案新增入我們剛剛建立的動態庫專案所在的同一解決方案。

然後,同樣在"應用程式嚮導" 中選擇 "控制台應用程式" 並選擇 "空專案"

5. 給dllcall專案新增**

首先,語句typedef int ( * lpaddfun)(int,int)定義了乙個與add函式接受引數型別和返回值均相同的函式指標型別。隨後,在main函式中定義了lpaddfun的例項addfun;

其次,在函式main中定義了乙個dll hinstance控制代碼例項hdll,通過win32 api函式loadlibrary動態載入了dll模組並將dll模組控制代碼賦給了hdll;

再次,在函式main中通過win32 api函式getprocaddress得到了所載入dll模組中函式add的位址並賦給了addfun。經由函式指標addfun進行了對dll中add函式的呼叫;

最後,應用工程使用完dll後,在函式main中通過win32 api函式freelibrary釋放了已經載入的dll模組。

通過這個簡單的例子,我們獲知dll定義和呼叫的一般概念:

(1)dll中需以某種特定的方式宣告匯出函式(或變數、類);

(2)應用工程需以某種特定的方式呼叫dll的匯出函式(或變數、類)。

5. 宣告dll匯出函式 

dll中匯出函式的宣告有兩種方式:

一種為4中lib.h例子中給出的在函式宣告 中加上__declspec(dllexport),這裡不再舉例說明;

另外一種方式是採用模組定義檔案(.def) 來宣告,.def檔案為鏈結器提供了有關被鏈結程式的匯出、屬性及其他方面的資訊。

具體不贅述

6. dll呼叫方式  

在第4節的例子中我們看到了由「loadlibrary-getprocaddress-freelibrary」系統api提供的三位一體「dll載入-dll函式位址獲取-dll釋放」方式,這種呼叫方式稱為dll的動態呼叫。

動態呼叫方式的特點是完全由程式設計者用 api 函式載入和解除安裝 dll,程式設計師可以決定 dll 檔案何時載入或不載入,顯式鏈結在執行時決定載入哪個 dll 檔案。

還有一種靜態呼叫方式的特點是由編譯系統完成對dll的載入和應用程式結束時 dll 的解除安裝。當呼叫某dll的應用程式結束時,若系統中還有其它程式使用該 dll,則windows對dll的應用記錄減1,直到所有使用該dll的程式都結束時才釋放它。靜態呼叫方式簡單實用,但不如動態呼叫方式靈活。

下面我們來看看靜態呼叫的例子

1. 新建乙個空的win32控制台應用程式testdll。(並且新建新的解決方案,而不用像4中一樣添入dll所在的解決方案)

2. 將第4節中 myfirstdll所生成的 .lib 和 .dll檔案拷貝到testdll.cpp所在目錄。

3. 編譯執行。

由上述**可以看出,靜態呼叫方式的順利進行需要完成兩個動作:

(1)告訴編譯器與dll相對應的.lib檔案所在的路徑及檔名,#pragma comment(lib,"dlltest.lib")就是起這個作用。

程式設計師在建立乙個dll檔案時,聯結器會自動為其生成乙個對應的.lib檔案,該檔案包含了dll 匯出函式的符號名及序號(並不含有實際的**)。在應用程式裡,.lib檔案將作為dll的替代檔案參與編譯。

(2)宣告匯入函式,extern "c" __declspec(dllimport) add(int x,int y)語句中的__declspec(dllimport)發揮這個作用。

靜態呼叫方式不再需要使用系統api來載入、解除安裝dll以及獲取dll中匯出函式的位址。這是因為,當程式設計師通過靜態鏈結方式編譯生成應用程式時,應用 程式中呼叫的與.lib檔案中匯出符號相匹配的函式符號將進入到生成的exe 檔案中,.lib檔案中所包含的與之對應的dll檔案的檔名也被編譯器儲存在 exe檔案內部。當應用程式執行過程中需要載入dll檔案時,windows將根據這些資訊發現並載入dll,然後通過符號名實現對dll 函式的動態鏈結。這樣,exe將能直接通過函式名呼叫dll的輸出函式,就象呼叫程式內部的其他函式一樣。

動態鏈結庫與靜態鏈結庫

有人會想,動態鏈結這樣麻煩,為什麼還要用呢?這裡有乙個技術問題,對這個問題的解決直接導致了動態載入的需求。問題是有些dll只在某個windows版本中存在,或某個api只在某些windows版本中被加入指定的dll。當你使用靜態鏈結的.exe試圖在不支援的windows版本上執行時,系統會彈出系統對...

靜態鏈結 庫 與動態鏈結 庫

靜態鏈結與動態鏈結 簡單的說,靜態庫和應用程式編譯在一起,在任何情況下都能執行,而動態庫是動態鏈結,顧名思義就是在應用程式啟動的時候才會鏈結,所以,當使用者的系統上沒有該動態庫時,應用程式就會執行失敗。再看它們的特點 動態庫 1.共享 多個應用程式可以使用同乙個動態庫,啟動多個應用程式的時候,只需要...

靜態鏈結庫與動態鏈結庫

靜態鏈結庫lib,在生成可執行檔案時,被全部嵌入到exe中,其顯式呼叫 pragma comment lib,lib 目標工程編譯鏈結之前需要將lib檔案和標頭檔案拷貝到工程目錄中。執行時不需要lib檔案。動態鏈結庫是在程式執行過程中,動態載入dll檔案中的函式來執行。因此dll檔案需要與exe檔案...