共用方式為


動態連結庫重新導向

DLL 載入器 是作系統 (OS) 的一部分,可解析 DLL 的參考、載入和連結。 動態連結庫 (DLL) 重新導向是其中一種技術,您可以藉此影響 DLL 載入器的行為,並控制它實際載入的數個候選 DLL 之一。

此功能的其他名稱包括 .localDot LocalDotLocal,以及 Dot Local Debugging

DLL 版本控制問題

如果您的應用程式相依於特定版本的共用 DLL,而另一個應用程式則與較新或較舊版本的該 DLL 一起安裝,則這可能會導致相容性問題和不穩定:它可能會導致您的應用程式開始失敗。

DLL 載入器會先查看呼叫行程從 (可執行檔的資料夾) 載入的資料夾中,再查看其他檔案系統位置。 因此,有一個因應措施是在可執行檔的資料夾中安裝應用程式所需的 DLL。 這實際上會使 DLL 成為私人的。

但這並不能解決 COM 的問題。 可以安裝並註冊兩個不相容的 COM 伺服器版本(即使在不同的文件系統位置中),但只有一個位置可以註冊 COM 伺服器。 因此,只會啟動最新的已註冊 COM 伺服器。

您可以使用重新導向來解決這些問題。

載入及測試私人二進位檔

DLL 載入器遵循的規則可確保系統 DLL 會從 Windows 系統位置載入,例如系統資料夾 (%SystemRoot%\system32)。 這些規則可避免植入攻擊:敵人將程式代碼放在可以寫入的位置,然後說服一些程式載入和執行它。 但是載入器的規則也使得在OS元件上工作更加困難,因為執行它們需要更新系統:這是一個非常有影響力的變化。

但是,您可以使用重新導向來載入 DLL 的私人復本(例如測試,或測量程式代碼變更的效能影響)。

如果您想要在公用 WindowsAppSDK GitHub 存放庫中參與原始程式碼,則您會想要測試變更。 同樣地,這是一個案例,您可以使用重新導向來載入私人 DLL 複本,而不是隨 Windows App SDK 隨附的版本。

您的選項

事實上,有兩種方式可確保您的應用程式使用您想要的 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&gt;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 "&lt;A.dll&gt;" copy /y "&lt;A.dll&gt;" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
            if EXIST "&lt;B.dll&gt;" copy /y "&lt;B.dll&gt;" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;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>

讓我們逐步解說該組態的一些用途。

  1. 為 Visual Studio 啟動但不偵錯 設定 PreBuildEvent (或 [開始偵錯] 體驗。

    <ItemDefinitionGroup>
      <PreBuildEvent>
    
  2. 請確定您在中繼目錄中有正確的資料夾結構。

    <!-- [[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
    
  3. 將您建置在本機的任何 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&gt;nul
      if EXIST "<path-to-local-dll>" copy /y "<path-to-local-dll>" $(IntDir)\microsoft.system.package.metadata\application.local 2&gt;nul
      </Command>
    </PreBuildEvent>
    
  4. 最後,表示您想要在部署的套件中包含特殊目錄及其內容。

    <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,您可以使用幾個簡單的步驟在目標裝置上達成相同的目的。

  1. 判斷套件的安裝資料夾。 您可以在 PowerShell 中發出 命令 Get-AppxPackage,並尋找傳回的 InstallLocation

  2. 請使用 InstallLocation 來變更 ACL,以允許自己建立資料夾/複製檔案。 編輯此文稿中的 <InstallLocation> 佔位元元,然後執行文稿:

    cd <InstallLocation>\Microsoft.system.package.metadata
    takeown /F . /A
    icacls  . /grant Administrators:F
    md <InstallLocation>\Microsoft.system.package.metadata\application.local
    
  3. 最後,手動將您於本機建置的任何 DLL(並想要以喜好方式使用系統部署的 DLL)複製到 application.local 目錄,然後 [重新] 啟動應用程式。

確認所有專案都正常運作

若要確認在運行時間載入正確的 DLL,您可以使用 Visual Studio 搭配附加的調試程式。

  1. 開啟 [模組] 視窗([偵錯>Windows>模組]。
  2. 尋找 DLL,並確定 路徑 指出重新導向的複本,而不是系統部署的版本。
  3. 確認只載入一份指定的 DLL。

如何重新導向未封裝應用程式的 DLL

重新導向檔案必須命名為 <your_app_name>.local。 因此,如果您的應用程式名稱是 Editor.exe,請將您的重新導向檔案命名為 Editor.exe.local。 您必須在可執行檔案的資料夾中安裝重新導向檔案。 您也必須在可執行檔案的資料夾中安裝 DLL。

會忽略重新導向檔案 內容;它本身的存在會導致 DLL 載入器在載入 DLL 時先檢查可執行檔的資料夾。 若要減輕 COM 問題,該重新導向會同時套用至完整路徑和部分名稱載入。 因此,重新導向會發生在 COM 案例中,而且不論指定為 LoadLibraryLoadLibraryEx的路徑為何。 如果在可執行文件的資料夾中找不到 DLL,則載入會遵循其一般搜尋順序。 例如,如果應用程式 C:\myapp\myapp.exe 使用下列路徑呼叫 LoadLibrary

C:\Program Files\Common Files\System\mydll.dll

如果 C:\myapp\myapp.exe.localC:\myapp\mydll.dll 同時存在,則 LoadLibrary 載入 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 的複本(而且不會造成您的應用程式失敗)。