2010-08-16 26 views
1

也許是個愚蠢的問題,但我不知道答案。使用GetModuleHandle或LoadLibrary加載dll(然後使用該dll的函數)並直接包含所需的標題有什麼區別?例如,使用的GetModuleHandle:GetModuleHandle和包含標題之間的區別

typedef void (WINAPI *PGNSI)(LPSYSTEM_INFO); 

// Call GetNativeSystemInfo if supported or GetSystemInfo otherwise. 

PGNSI pGNSI; 
SYSTEM_INFO si; 

ZeroMemory(&si, sizeof(SYSTEM_INFO)); 

pGNSI = (PGNSI) GetProcAddress(
    GetModuleHandle(TEXT("kernel32.dll")), 
    "GetNativeSystemInfo"); 
if(NULL != pGNSI) 
    pGNSI(&si); //calling function through pointer 
else GetSystemInfo(&si); 

但我可以包括WINDOWS.H頭直接調用該函數從我的代碼:

#include <windows.h> 

SYSTEM_INFO si; 
ZeroMemory(&si, sizeof(SYSTEM_INFO)); 
GetNativeSystemInfo(&si); 

這同樣適用於例如OPENGL32.DLL,我不知道在我的項目中包含opengl函數的頭文件是否更好,或者使用Getmodulehandle和GetProcAdress來調用所需的函數。有什麼不同?以某種方式使用getmodulehandle好處的第一種方法?感謝您的回答。

+0

GetNativeSystemInfo()是特殊的,它不可用在早期版本的Windows中。你真的應該使用GetProcAddress。這不適用於opengl。 – 2010-08-16 14:29:53

+0

GetNativeSystemInfo()只是一個例子,但正如我現在看到的,這是一個很好的例子,現在我明白了,謝謝 – sanjuro 2010-08-17 14:13:26

回答

6

首先,確保你明白,GetModuleHandleLoadLibrary不完全等同

調用LoadLibrary也很有用。但是,由於這不是你問題的直接部分,所以我會留下一個大的解釋,並建議你確保理解這兩個鏈接中的文檔。


要直接使用dll函數,就好像它和其他函數一樣,不要只包含頭文件。除了頭文件之外,您的項目中的某處還被告知要鏈接到相應的lib文件。在你的例子中,它將是kernel32.lib。這可以通過各種方式完成,例如項目中的鏈接器設置或文件中的#pragma comment (lib, ...)

當一個程序是這樣構建的時,編譯器編寫代碼來在程序啓動時加載該dll。如果在實際嘗試運行程序時找不到有問題的dll,則會失敗並顯示錯誤消息。您無法編寫代碼來捕捉失敗並採取一些替代操作。

對於作爲操作系統的一部分(如kernel32.dll)或至少通常與它一起提供的dll,此即時加載行爲不是問題,因爲您可以安全地假定dll將始終存在。另一方面,如果你要建立一個通常不存在的dll,那麼你會有更多的關注。要麼你必須確保這樣一個dll與你的程序一起發佈,否則以某種方式嘗試確保用戶安裝任何其他必要的包來在他們的系統上獲取該dll。

此外,如果DLL加載,但任何你想從DLL使用的功能實際上並不在它的存在,那麼它會立即失敗與錯誤信息。 (它不會等到你的程序嘗試調用該函數時,它會在程序啓動並中止時發現這種差異。)如果世界上存在不同版本的dll,這可能會成爲問題。

現在,當您使用LoadLibrary/GetProcAddress時,您需要在您選擇時加載dll並要求查找該dll提供的特定功能。如果其中任何一個步驟失敗,您就有能力編寫代碼以合理的方式處理它。

這可以用於各種用途。例如,您可以創建一個插件機制,讓程序從一些特定的文件夾中即時搜索並加載插件dll。由於程序不會提前知道哪些插件會存在,所以LoadLibrary是唯一的方法。

另一件事調用LoadLibrary/GetProcAddress的,可用於爲加載DLL並從中調用一個函數,即使你沒有正確的頭文件和lib文件。如果你知道dll的名稱,函數的名稱和函數的確切簽名(參數類型,返回類型,調用約定),那麼你就有足夠的代碼來加載該dll併成功調用該函數。偶爾這可能會有用。例如,人們可以使用Windows dll提供的某些「無證」功能。

最後,調用LoadLibrary /的GetModuleHandle/GetProcAddress的可以用來讓你使用,這並不一定上要支持所有的操作系​​統中存在的功能。這似乎是您的代碼片段的原因,它調用GetNativeSystemInfoGetSystemInfo。前者僅在WinXP/2003上可用,而後者在Win2000上可用。如果代碼剛剛被寫爲GetNativeSystemInfo的直接調用,那麼該程序將無法在Windows 2000上運行。但是,您在那裏檢查GetNativeSystemInfo是否存在於當前操作系統上,並且僅在使用該操作系統時才使用它,否則它會回到更廣泛支持的GetSystemInfo。

因此,在您的示例中,您選擇調用該功能的技術取決於您打算支持哪種操作系統。如果你的軟件不需要在Windows 2000上運行,那麼直接調用GetNativeSystemInfo就容易多了(最有可能的是最好的方法)。

+0

thx爲您詳盡的解釋 – sanjuro 2010-08-17 14:10:52

1

GetModuleHandle使您可以動態加載dll,可以使用哪些實例來實現插件或按需加載某些資源。
下面,兩種方法之間沒有區別 - 鏈接的靜態庫只包含程序啓動時(C語言)時執行動態鏈接的代碼。

+0

當我包含頭文件和可選的#pragma註釋(lib,「opengl32.lib」)我指定庫它意味着我靜態鏈接? – sanjuro 2010-08-16 13:19:03

+0

不,(lib,)只是顯示鏈接器在哪裏查找庫;的確我不認爲將dll鏈接爲靜態庫是可能的。 – mbq 2010-08-16 13:26:23

+0

@san:有區別,當你連接到opengl32.lib時不需要使用GetProcAddress。這真的是你想要的,在opengl上使用GPA會非常痛苦。不必要的。 – 2010-08-16 14:28:34

1

這取決於,在這種情況下,我會說它正在使用,以便dll/exe不會從窗口LDR加載錯誤,如果系統(kernel32.dll等)沒有導出的二進制文件可能使用,onr很好的例子是Windows XP的DEP功能,它只存在於SP 2+中,但它不是一個強制強制所需SP的好主意,因爲它可以減少程序的可用觀衆。 OpenGL的使用相同的幾分原理,由於這一事實,一個不能預測的API支持(和擴展),因此必須檢查它,然後將其導入或與wglGetProcAddress

另一個原因,這是更可替代'廉價'是這樣的,人們不必鏈接到某些庫幷包含某些頭文件,特別是如果您使用從一個非常大的SDK只說1個函數,這可以防止其他開發人員浪費時間來獲得巨大的SDK(他們ofc將需要二進制連續導出)

3

某些函數不存在於舊版本的Windows中,並且當您直接調用某個函數時,該函數將以您的程序的導入表結尾。如果Windows無法在導入表中找到其中一個功能,則該程序根本無法運行。如果你想支持第三方插件等

0

LoadLibraryGetModulehandle這兩者都適用於相同的材料,即;他們會在運行時將模塊映射到進程上,但在LoadLibrary的情況下,它會增加內核透視圖中的引用計數,因爲後者不會這樣做。