動態連結程式庫重新導向
DLL 載入器 是作業系統 (OS) 的一部分,可解析 DLL 的參考、載入和連結 DLL。 動態連結程式庫 (DLL) 重新導向是其中一種技術,可讓您影響 DLL 載入器 的行為 ,並控制它實際載入的數個候選 DLL 之一。
這項功能的其他名稱包括 .local 、 Dot Local 、 DotLocal 和 Dot Local 偵錯 。
DLL 版本控制問題
如果您的應用程式相依于特定版本的共用 DLL,而另一個應用程式則與較新或較舊版本的該 DLL 一起安裝,則這可能會導致相容性問題和不穩定:它可能會導致您的應用程式開始失敗。
DLL 載入器會先查看呼叫進程從 (可執行檔的資料夾) 載入的 資料夾中,再查看其他檔案系統位置。 因此,有一個因應措施是在可執行檔的 資料夾中安裝應用程式所需的 DLL。 這實際上會使 DLL 成為私人的。
但這並不能解決 COM 的問題。 可以安裝並註冊兩個不相容的 COM 伺服器版本(即使在不同的檔案系統位置中),但只有一個位置可以註冊 COM 伺服器。 因此,只會啟動最新的已註冊 COM 伺服器。
您可以使用重新導向來解決這些問題。
載入及測試私人二進位檔
DLL 載入器遵循的規則可確保系統 DLL 會從 Windows 系統位置載入,例如系統資料夾 ( %SystemRoot%\system32
)。 這些規則可避免植入攻擊:敵人將程式碼放在可以寫入的位置,然後說服一些程式載入和執行它。 但是載入器的規則也使得在 OS 元件上工作更加困難,因為執行它們需要更新系統:這是一個非常有影響力的變化。
但是,您可以使用重新導向來載入 DLL 的私人複本(例如測試,或測量程式碼變更的效能影響)。
如果您想要參與公用 WindowsAppSDK GitHub 存放庫中的原始程式碼,則您會想要測試變更。 同樣地,這是一個案例,您可以使用重新導向來載入 DLL 的私人複本,而不是隨附于Windows 應用程式 SDK的版本。
您的選項
事實上,有兩種方式可確保您的應用程式使用您想要的 DLL 版本:
- DLL 重新導向。 如需詳細資訊,請繼續閱讀本主題。
- 並存元件。 在隔離應用程式和並存元件 主題 中說明。
提示
如果您是開發人員或系統管理員,則應該針對現有的應用程式使用 DLL 重新導向。 這是因為它不需要對應用程式本身進行任何變更。 但是,如果您要建立新的應用程式或更新現有的應用程式,而且您想要將應用程式與潛在問題隔離,請建立並存元件。
選擇性:設定登錄
若要啟用全電腦的 DLL 重新導向,您必須建立新的登錄值。 在機碼 HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options
底下,建立名為 DevOverrideEnable 的新 DWORD 值。 將值設定為 1,然後重新開機電腦。 或使用下列命令(並重新啟動電腦)。
reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" /v DevOverrideEnable /t REG_DWORD /d 1
設定該登錄值時,即使應用程式具有應用程式資訊清單,也一樣會遵守 DotLocal DLL 重新導向。
建立重新導向檔案或資料夾
若要使用 DLL 重新導向,您將建立 重新導向檔案 或 重新導向資料夾 (視您擁有的應用程式類型而定),如本主題稍後的章節所示。
如何重新導向已封裝應用程式的 DLL
封裝的應用程式需要 DLL 重新導向的特殊資料夾結構。 下列路徑是啟用重新導向時載入器看起來的位置:
<Drive>:\<path_to_package>\microsoft.system.package.metadata\application.local\
如果您能夠編輯您的 .vcxproj
檔案,則使用您的套件建立和部署該特殊資料夾的便利方式,就是將一些額外的步驟新增至 您的 .vcxproj
組建:
<ItemDefinitionGroup>
<PreBuildEvent>
<Command>
del $(FinalAppxManifestName) 2>nul
<!-- [[Using_.local_(DotLocal)_with_a_packaged_app]] This makes the extra DLL deployed via F5 get loaded instead of the system one. -->
if NOT EXIST $(IntDir)\microsoft.system.package.metadata\application.local MKDIR $(IntDir)\microsoft.system.package.metadata\application.local
if EXIST "<A.dll>" copy /y "<A.dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2>nul
if EXIST "<B.dll>" copy /y "<B.dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2>nul
</Command>
</PreBuildEvent>
</ItemDefinitionGroup>
<ItemGroup>
<!-- Include any locally built system experience -->
<Media Include="$(IntDir)\microsoft.system.package.metadata\application.local\**">
<Link>microsoft.system.package.metadata\application.local</Link>
</Media>
</ItemGroup>
讓我們逐步解說該組態的一些用途。
設定 Visual Studio [啟動但不 偵錯] 體驗的 [ 或開始偵錯 ]。
PreBuildEvent
<ItemDefinitionGroup> <PreBuildEvent>
請確定您在中繼目錄中有正確的資料夾結構。
<!-- [[Using_.local_(DotLocal)_with_modern_apps]] This makes the extra DLL deployed via Start get loaded instead of the system one. --> if NOT EXIST $(IntDir)\microsoft.system.package.metadata\application.local MKDIR $(IntDir)\microsoft.system.package.metadata\application.local
將您在本機建置的任何 DLL(並想要優先使用系統部署的 DLL)複製到
application.local
目錄中。 您可以從任何地方挑選 DLL(我們建議您針對使用.vcxproj
可用的宏)。 只要確定這些 DLL 會在這個專案之前建置;否則會遺失它們。 此處會顯示兩 個範本 複製命令;視需要使用多個範本複製命令,並編輯<path-to-local-dll>
預留位置。if EXIST "<path-to-local-dll>" copy /y "<path-to-local-dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2>nul if EXIST "<path-to-local-dll>" copy /y "<path-to-local-dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2>nul </Command> </PreBuildEvent>
最後,表示您想要在部署的套件中包含特殊目錄及其內容。
<ItemGroup> <!-- Include any locally built system experience --> <Media Include="$(IntDir)\microsoft.system.package.metadata\application.local\**"> <Link>microsoft.system.package.metadata\application.local</Link> </Media> </ItemGroup>
這裡所述的方法(使用中繼目錄)會讓您的原始程式碼控制項登記保持乾淨,並降低不小心認可已編譯二進位檔的可能性。
接下來,您需要做的就是(重新)部署專案。 若要取得全新的完整部署,您可能也必須卸載/清除目標裝置上的現有部署。
手動複製二進位檔
如果您無法以上述方式使用 , .vcxproj
您可以使用幾個簡單的步驟在目標裝置上達成相同的目的。
判斷套件的安裝資料夾。 您可以在 PowerShell 中發出 命令
Get-AppxPackage
,並尋找傳回的 InstallLocation 來執行此動作。使用 InstallLocation 來變更 ACL,以允許自己建立資料夾/複製檔案。
<InstallLocation>
編輯此腳本中的預留位置,然後執行腳本:cd <InstallLocation>\Microsoft.system.package.metadata takeown /F . /A icacls . /grant Administrators:F md <InstallLocation>\Microsoft.system.package.metadata\application.local
最後,手動將您已在本機建置的任何 DLL(並想要以喜好方式使用系統部署的 DLL)複製到
application.local
目錄,然後 [re]啟動應用程式。
確認所有專案都正常運作
若要確認在執行時間載入正確的 DLL,您可以使用 Visual Studio 搭配附加的偵錯工具。
- 開啟 [模組 ] 視窗 ( 偵 錯 > Windows > 模組)。
- 尋找 DLL,並確定 Path 指出重新導向的複本,而不是系統部署的版本。
- 確認只載入一份指定的 DLL。
如何重新導向未封裝應用程式的 DLL
重新導向檔案必須命名為 <your_app_name>.local
。 因此,如果您的應用程式名稱是 Editor.exe
,則請將重新導向檔案 Editor.exe.local
命名為 。 您必須在可執行檔的 資料夾中安裝重新導向檔案。 您也必須在可執行檔的 資料夾中安裝 DLL。
重新導向檔案的內容 會被忽略;它的存在會讓 DLL 載入器在載入 DLL 時先檢查可執行檔的資料夾。 若要減輕 COM 問題,該重新導向會同時套用至完整路徑和部分名稱載入。 因此,不論 LoadLibrary 或 LoadLibraryEx 指定的 路徑為何,重新導向也會發生在 COM 案例中。 如果在可執行檔的 資料夾中找不到 DLL,則載入會遵循其一般搜尋順序。 例如,如果應用程式 C:\myapp\myapp.exe
使用下列路徑呼叫 LoadLibrary :
C:\Program Files\Common Files\System\mydll.dll
如果 和 都存在 C:\myapp\myapp.exe.local
,則 LoadLibrary 會載入 C:\myapp\mydll.dll
。 C:\myapp\mydll.dll
否則, LoadLibrary 會載入 C:\Program Files\Common Files\System\mydll.dll
。
或者,如果名為 C:\myapp\myapp.exe.local
的資料夾存在,而且它包含 mydll.dll
,則 LoadLibrary 會載入 C:\myapp\myapp.exe.local\mydll.dll
。
如果您使用 DLL 重新導向,且應用程式無法依搜尋順序存取所有磁片磁碟機和目錄,則 LoadLibrary 會在拒絕存取時立即停止搜尋。 如果您 未 使用 DLL 重新導向, 則 LoadLibrary 會略過無法存取的目錄,然後繼續搜尋。
最好在包含應用程式的相同資料夾中安裝應用程式 DLL;即使您未使用 DLL 重新導向也一樣。 這可確保安裝應用程式不會覆寫 DLL 的其他複本(因而導致其他應用程式失敗)。 此外,如果您遵循這個良好的做法,則其他應用程式不會覆寫 DLL 的複本(而且不會造成您的應用程式失敗)。