【Windows下DLL查找順序 】

1、寫做初衷 ios

在Windows下單個DLL可能存在多個不一樣的版本,若不特別指定DLL的絕對路徑或使用其餘手段指定,在應用程序加載DLL時可能會查找到錯誤的版本,進而引出各類莫名其妙的問題。本文主要考慮如下兩個方面:windows

a. 參考MSDN,給出Windows下DLL查找順序安全

b. 簡單使用ProcessMonitor來驗證DLL查找順序app

 

2、DLL查找順序 函數

(本部分多數內容是參考MSDN上的Dynamic-Link Library Search Order一文,連接以下http://msdn.microsoft.com/en-us/library/ms682586(v=vs.85).aspx。多數爲翻譯,有部份內容修改。本文僅關注桌面應用程序的查找順序,對於Windows Store apps請參考MSDN原文。)工具

1. DLL查找路徑基礎spa

應用程序能夠經過如下方式控制一個DLL的加載路徑:使用全路徑加載、使用DLL重定向、使用manifest文件。若是上述三種方式均未指定,系統查找DLL的順序將按照本部分描述的順序進行。命令行

對於如下兩種狀況的DLL,系統將不會查找,而是直接加載:線程

a. 對於已經加載到內存中的同名DLL,系統使用已經加載的DLL,而且忽略待加載DLL的路徑。(注意對某個進程而言,系統已經加載的DLL必定是惟一的存在於某個目錄下。)翻譯

b. 若是該DLL存在於某個Windows版本的已知DLL列表(unkown DLL)中,系統使用已知DLL的拷貝(包括已知DLL的依賴項)。已知DLL列表能夠從以下注冊表項看到:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\KnownDLLs。

這裏有個比較坑的地方,對於有依賴項的DLL(即便使用全路徑指定DLL位置),系統查找其所依賴DLL的方法是按照實際的模塊名稱來的,所以若是加載的DLL不在系統查找順序目錄下,那麼動態加載該DLL(LoadLibrary)會返回一個"找不到模塊"的錯誤。

 

2. 系統標準DLL查找順序

系統使用的標準DLL查找順序依賴因而否設置了"安全DLL查找模式"(safe DLL search mode)。"安全DLL查找模式"會將用戶當前目錄置於查找順序的後邊。

"安全DLL查找模式"默認是啓用的,禁用的話,能夠將註冊表項HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Session Manager\SafeDllSearchMode設爲0。調用SetDllDirectory函數能夠禁用"安全DLL查找模式",並修改DLL查找順序。

Windows XP下,"安全DLL查找模式"默認是禁用的,須要啓用該項的話,在註冊表中新建一個SafeDllSearchMode子項,並賦值爲1便可。"安全DLL查找模式"從Windows XP SP2開始,默認是啓用的。

 

啓用"安全DLL查找模式"時,查找順序以下:

a. 應用程序所在目錄;

b. 系統目錄。GetSystemDirectory返回的目錄,一般是系統盤\Windows\System32;

c. 16位系統目錄。該項只是爲了向前兼容的處理,能夠不考慮;

d. Windows目錄。GetWindowsDirectory返回的目錄,一般是系統盤\Windows

e. 當前目錄。GetCurrentDirectory返回的目錄;

f. 環境變量PATH中全部目錄。

 

若是"安全DLL查找模式"被禁用,查找順序以下:

a. 應用程序所在目錄;

b. 當前目錄。GetCurrentDirectory返回的目錄;

c. 系統目錄。GetSystemDirectory返回的目錄,一般是系統盤\Windows\System32;

d. 16位系統目錄。該項只是爲了向前兼容的處理,能夠不考慮;

e. Windows目錄。GetWindowsDirectory返回的目錄,一般是系統盤\Windows

f. 環境變量PATH中全部目錄。

 

3. 修改系統DLL查找順序

系統使用的標準DLL查找順序能夠經過如下兩種方式調整:

3.1 使用LOAD_WITH_ALTERED_SEARCH_PATH標誌調用LoadLibraryEx函數;

這種方式調用LoadLibraryEx函數,須要設置lpFileName參數(絕對路徑)。與標準查找策略不一樣的是,使用LOAD_WITH_ALTERED_SEARCH_PATH標誌調用LoadLibraryEx函數的DLL查找順序將"查找應用程序所在目錄"修改成lpFileName指定的目錄。

3.2 調用SetDllDirectory函數。

注意:SetDllDirectory函數在Windows XP SP1開始支持的。

函數SetDllDirectory在調用參數lpPathName是一個路徑時,可支持修改DLL搜索路徑。修改以後的搜索順序以下:

a. 應用程序所在目錄;

b. 函數SetDllDirectory參數lpPathName給定的目錄;

c. 系統目錄。GetSystemDirectory返回的目錄,一般是系統盤\Windows\System32;

d. 16位系統目錄。該項只是爲了向前兼容的處理,能夠不考慮;

e. Windows目錄。GetWindowsDirectory返回的目錄,一般是系統盤\Windows

f. 環境變量PATH中全部目錄。

若是lpPathName參數爲空字符串,這樣就會把當前目錄從DLL搜索路徑中去掉。

若是用NULL參數調用SetDllDirectory函數,能夠恢復按照系統註冊表的"安全DLL查找模式"來查找DLL。

 

固然win8或者windows server 2012提供更多的可定製方法,這個能夠參考MSDN上介紹。好比:SetDefaultDllDirectories、 AddDllDirectoryRemoveDllDirectory

 

3、ProcessMonitor使用

ProcessMonitor能夠從http://technet.microsoft.com/en-us/sysinternals/bb896645下載。

官網給出的介紹資料以下:

Process Monitor一款系統進程監視軟件,整體來講,Process Monitor至關於Filemon+Regmon,其中的Filemon專門用來監視系統 中的任何文件操做過程,而Regmon用來監視註冊表的讀寫操做過程。 有了Process Monitor,使用者就能夠對系統中的任何文件和 註冊表操做同時進行監視和記錄,經過註冊表和文件讀寫的變化, 對於幫助診斷系統故障或是發現惡意軟件、病毒或木馬來講,很是 有用。

軟件下載以後,解壓就能夠直接運行。Process Monitor默認會啓用針對真當前系統的"File System"、"Registry"、"Process"的全部操做的記錄,相似wireshark網卡抓包軟件,只是抓取的信息不一樣。若是僅關心某個進程的事件,能夠在工具欄或者菜單中選擇Filter-Filiter,彈出下圖所示對話框:

舉個例子,咱們只關心進程名爲"qwe.exe"的相關操做,能夠作以下處理:從第一個下拉列表框中選擇ProcessName,將進程名字填入輸入框,而後點擊"Add"按鈕,點擊 "OK"(若是已經開始監測,能夠直接點Apply按鈕)。

其餘關於Process Monitor的使用能夠參考幫助文檔,介紹總體比較詳細,這裏不作贅述。

 

4、驗證Windows下DLL加載順序是否正確

那麼咱們能夠考慮在win7下驗證下DLL加載順序,想法很簡單,隨便寫一個系統中不存在的DLL,用LoadLibray動態加載下看看,用Process Monitor記錄當前進程的操做記錄。

代碼以下:

複製代碼
 1 #include <windows.h>
 2 #include <iostream>  3  4 int main(int argc, char ** argv)  5 {  6 using std::cout;  7 using std::endl;  8  9 // 隨便設置一個不存在的dll名 10 HMODULE hMod = LoadLibrary("123.dll"); 11 12 if (NULL != hMod) 13  FreeLibrary(hMod); 14 15 cout << "LoadLibrary Test" << endl; 16 17 return 0; 18 }
複製代碼

 

使用MinGW編譯以後,在命令行下運行該程序。Process Monitor輸出以下信息(這裏僅截取關於123.dll加載的信息):

能夠看到這裏搜索的路徑跟系統標準DLL搜索路徑時一致的。個人環境變量Path從D:\software\Subversion\Apache2\bin開始到D:\software\tortoiseGit\bin結束。

 

5、總結

本文主要介紹了Windows下DLL查找順序,理清這個查找順序基本能夠找到LoadLibrary返回NULL,提示"找不到指定模塊"的緣由。一般能夠考慮一下幾點:

a. 待加載DLL文件是正確的、完整的嗎? 是否有損壞? 加載全路徑是否正確?

b. 待加載DLL的依賴項是否存在?(Dependency Walker能夠查看依賴性)這些依賴項在是否都在系統能夠查找到的目錄下?

另外,本文簡單介紹了使用Process Monitor分析程序運行對文件系統、註冊表、進程/線程的操做,工具不錯,有待開發。

還有一個問題,須要特別注意的是當前目錄,由於不少狀況下當前目錄會由於SetCurrentDirectory或者OpenFile的操做而改變,某些狀況下會對加載DLL形成意外的麻煩。

 

注:版權全部,請勿用於商業用途,轉載請註明原文地址。本人保留全部權利

相關文章
相關標籤/搜索