2008年12月2日

Visual C++ -- DLL

http://eason982.blogspot.com/2008/12/visual-c-dll.html
http://0rz.tw/fd56e


動態連結程式庫 (DLL) 是具有函式的共用程式庫功能的可執行檔。動態連結提供一種方法,讓處理序 (Process) 呼叫不是可執行程式碼部分的函式。函式的可執行程式碼位於 DLL 裡,它包含一或多個已編譯、連結的函式,並且儲存在與使用它們的處理序不同的地方。DLL 也有助於共用資料和資源。多個應用程式可以同時存取記憶體中 DLL 單一複本的內容。

動態連結與靜態連結的不同處在於,前者允許可執行模組 (.DLL 或 .EXE 檔) 只包含在執行階段時用來找出 DLL 函式可執行程式碼的所需資訊。在靜態連結中,連結器 (Linker) 會從靜態連結程式庫取得所有參考函式,並且將它與您的程式碼一起放入可執行檔。

不使用靜態連結而改用動態連結可提供許多優點。DLL 節省記憶體、降低交換、節省磁碟空間、較容易升級、提供售後支援、提供擴充 MFC 程式庫類別機制、支援多種語言程式和簡化國際版本的建立。


LoadLibrary 和 AfxLoadLibrary
使用 LoadLibrary 和 AfxLoadLibrary 明確連結到 DLL 的方式

處理序會呼叫 LoadLibrary (或 AfxLoadLibrary) 來明確連結至 DLL。若是成功,函式會將特定 DLL 對應到呼叫處理序的位址空間,並將控制代碼傳回給其他明確連結的函式 (例如 GetProcAddress 和 FreeLibrary) 所使用到的 DLL。

LoadLibrary 會嘗試依照和隱含連結相同的搜尋順序來找出 DLL。如果系統無法找出 DLL 或者如果進入點函式傳回 FALSE,LoadLibrary 就會傳回 NULL。如果 LoadLibrary 的呼叫指定已經對應到呼叫處理序的位址空間之 DLL 模組,函式便只會傳回 DLL 的控制代碼,並遞增模組的參考次數 (Reference Count)。

作業系統會在 DLL 擁有進入點函式時,呼叫名為 LoadLibrary 執行緒內容中的函式。如果 DLL 已經連結至處理序,就不會呼叫進入點函式,因為先前 LoadLibrary 的呼叫並沒有包含 FreeLibrary 函式的對應呼叫。

載入擴充 DLL 的 MFC 應用程式應該使用 AfxLoadLibrary 而不是 LoadLibrary。AfxLoadLibrary 會在呼叫 LoadLibrary 之前處理執行緒同步處理。AfxLoadLibrary 的介面 (函式原型) 與 LoadLibrary 相同。

如果因為某些原因使得 Windows 無法載入 DLL,處理序可以嘗試從錯誤復原。例如,處理序將錯誤告知使用者,並且讓使用者指定 DLL 的另一個路徑。


GetProcAddress
使用 GetProcAddress 取得 DLL 中匯出函式 (Exported Function) 的位址

明確連結至 DLL 的處理序會呼叫 GetProcAddress 來獲得 DLL 裡匯出函式的位址。您可以使用傳回的函式指標來呼叫 DLL 函式。GetProcAddress 會將 DLL 模組控制代碼 (由 LoadLibrary、AfxLoadLibrary 或 GetModuleHandle 傳回) 和您要呼叫的函式名稱或函式的匯出序數當做參數來使用。
因為 DLL 函式是經由指標呼叫,而且沒有編譯時期型別檢查,請確定函式的參數是正確的,以防止您逾越堆疊的記憶體配置和造成存取違規。一個提供型別安全的方式是檢視匯出函式的函式原型,並為函式指標建立相符的 Typedef。例如:



typedef UINT (CALLBACK* LPFNDLLFUNC1)(DWORD,UINT);
...

HINSTANCE hDLL; // Handle to DLL
LPFNDLLFUNC1 lpfnDllFunc1; // Function pointer
DWORD dwParam1;
UINT uParam2, uReturnVal;

hDLL = LoadLibrary("MyDLL");
if (hDLL != NULL)
{
lpfnDllFunc1 = (LPFNDLLFUNC1)GetProcAddress(hDLL,
"DLLFunc1");
if (!lpfnDllFunc1)
{
// handle the error
FreeLibrary(hDLL);
return SOME_ERROR_CODE;
}
else
{
// call the function
uReturnVal = lpfnDllFunc1(dwParam1, uParam2);
}
}


呼叫 GetProcAddress 時的所需函式指定方式是根據 DLL 建置方式而決定的。
如果要連結的 DLL 是以模組定義 (.def) 檔建置,且序數和函式並列於 DLL 的 .def 檔之 EXPORTS 區段中,則您只能取得匯出序數。相對於使用函式名稱,如果 DLL 有許多匯出函式,以匯出序數呼叫 GetProcAddress 會稍微快些,因為匯出序數會被當成 DLL 匯出表的索引。有了匯出序數,GetProcAddress 可以直接找出函式,相反做法則是在 DLL 匯出表的函式名稱比較指定名稱。然而,只有當您可以控制 .def 檔案裡匯出函式的序數指派時,才應該以匯出序數呼叫 GetProcAddress。


FreeLibrary 和 AfxFreeLibrary
討論在不再需要 DLL 模組時使用 FreeLibrary 和 AfxFreeLibrary 的方式

當不再需要 DLL 模組時,明確連結至 DLL 的處理序會呼叫 FreeLibrary 函式。這個函式會遞減模組的參考次數,並在參考到的次數為零的時候,解除它在處理序的位址空間的對應。
MFC 應用程式應該使用 AfxFreeLibrary,而不是 FreeLibrary 來卸載擴充 DLL。AfxFreeLibrary 的介面 (函式原型) 與 FreeLibrary 相同。

...
..
.

See reference link

沒有留言: