本文將討論以下問題:
(1)Windows可執行程序會從哪些目錄下加載DLL.
(2)如何將可執行使用的DLL放置到統一的目錄下,而不是與EXE同一目錄.
(3)可執行程序加載了不該加載的DLL.
(4)Win7,Win8下,"\Windows\System32"中的可執行程序無法加載DLL.
(1)
當啟動一個可執行程序時,如果該程序需要加載其他DLL,那么當DLL的路徑不是完整路徑時,會先從當前目錄下查找,找不到會再搜索系統目錄,還是找不到的話,則依次搜索環境變量path的目錄.這個順序很重要.
我自己系統的默認環境變量path的目錄如下:
C:\Program Files (x86)\Microsoft DirectX SDK (June 2007)\Utilities\Bin\x86;C:\Windows\system32;C:\Windows;C:\Windows\System32\Wbem;C:\Windows\System32\WindowsPowerShell\v1.0\;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x86;C:\Program Files (x86)\Intel\OpenCL SDK\2.0\bin\x64;C:\Program Files\TortoiseSVN\bin;c:\Program Files (x86)\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\Tools\Binn\;c:\Program Files\Microsoft SQL Server\100\DTS\Binn\;c:\Program Files (x86)\Microsoft SQL Server\90\Tools\binn\;;C:\Program Files (x86)\Microsoft Visual Studio 9.0\;C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin
(2)
為了發布的軟件目錄清晰,我通常會將應用程序使用到的DLL放到一個統一的目錄下,方法就是設置path環境變量.
在VC環境下可以通過以下代碼設置path環境變量:
1 // 設置Path環境變量
2 char szOldPathBuffer[4096] = { 0 }; 3 char szCurrPath[256] = { 0 }; 4 char szNewPathBuffer[4096] = { 0 }; 5 ::GetEnvironmentVariable("Path", szOldPathBuffer, sizeof(szOldPathBuffer)); 6 ::GetCurrentDirectory(sizeof(szCurrPath), szCurrPath); 7 ::sprintf(szNewPathBuffer, 8 "%s\\ExternDll;%s", 9 szCurrPath, szOldPathBuffer); 10
11 if(!::SetEnvironmentVariable("Path", szNewPathBuffer)) 12 { 13 ::MessageBox(NULL, szNewPathBuffer, "ERROR: Set Environment Failed!", 0); 14 }
(3)
這樣做可能會碰到問題,就是應用程序加載了不該加載的DLL.
舉個例子,應用程序中需要使用一個DLL為"physxcore.dll",將這個DLL放到某個path環境變量目錄中.而用戶的系統目錄下恰好也存在一個physxcore.dll.如果兩個physxcore.dll版本不一致,那么你的應用程序很可能無法啟動,或者出現莫名其妙的問題.這是我親身經歷的問題,當時覺得很奇怪,若干台同樣配置的機器,怎么就偏偏有一台不能運行呢?不知道這台機器裝了什么軟件,該軟件將這個physxcore.dll放置到了系統目錄下.解決辦法就是將physxcore.dll放到與EXE文件同目錄下.
(4)
我做過測試,如果將應用程序放到WIN7,WIN8的"\Windows\System32"目錄下,它將不法加載任何DLL,無論是顯示加載還是隱式加載.這個問題困擾了我很久,因為我寫過幾個屏保程序,這些程序在XP下設置屏保很正常,但Win7,Win8下就是無法運行.至今我也沒有找到什么合理的解釋.但可以將應用程序放到"\Windows\syswow64"或"\Windows\syswow32",程序放到這個目錄下,也能夠以屏保的方式運行.