DLL-Umleitung (Dynamic Link Library)

Das DLL-Ladeprogramm ist der Teil des Betriebssystems (OS), der Verweise auf DLLs auflöst, die DLLs lädt und verknüpft. Die DLL-Umleitung (Dynamic Link Library) ist eine der Techniken, mit denen Sie das Verhalten des DLL-Ladeprogramms beeinflussen und steuern können, welche von mehreren möglichen DLLs tatsächlich geladen wird.

Weitere Namen für dieses Feature sind .local, Dot Local, DotLocal und Dot Local Debugging.

DLL-Versionsprobleme

Wenn Ihre Anwendung von einer bestimmten Version einer freigegebenen DLL abhängt und eine andere Anwendung mit einer neueren oder älteren Version dieser DLL installiert wird, kann dies zu einem Kompatibilitätsproblem und Instabilität führen. Es kann passieren, dass Ihre App in einem solchen Fall nicht mehr gestartet werden kann.

Das DLL-Ladeprogramm sucht in dem Ordner, aus dem der aufrufende Prozess geladen wurde (Ordner der ausführbaren Datei), bevor es an anderen Speicherorten im Dateisystem sucht. Daher besteht eine Problemumgehung darin, die für Ihre App erforderliche DLL im Ordner Ihrer ausführbaren Datei zu installieren. Dadurch wird die DLL effektiv als privat festgelegt.

Diese Vorgehensweise löst aber nicht das Problem für COM (Component Object Model). Es ist möglich, zwei inkompatible Versionen eines COM-Servers zu installieren und zu registrieren (sogar an verschiedenen Dateisystemspeicherorten), aber es gibt nur einen Ort zum Registrieren des COM-Servers. Daher wird nur der zuletzt registrierte COM-Server aktiviert.

Sie können die Umleitung verwenden, um diese Probleme zu beheben.

Laden und Testen privater Binärdateien

Die Regeln, die das DLL-Ladeprogramm befolgt, stellen sicher, dass System-DLLs aus den Windows-Systemspeicherorten geladen werden, z. B. aus dem Systemordner (%SystemRoot%\system32). Diese Regeln verhindern Binary Planting-Angriffe: Bei einem solchen Angriff fügen Angreifer*innen Code ein, den sie an einem Ort geschrieben haben, auf den sie Schreibzugriff haben, und veranlassen dann einen Prozess dazu, den Code zu laden und auszuführen. Die Regeln des Ladeprogramms erschweren aber auch die Bearbeitung von Betriebssystemkomponenten, da ihre Ausführung eine Aktualisierung des Systems erfordert. Dies ist eine sehr wirksame Änderung.

Sie können die Umleitung jedoch verwenden, um private Kopien von DLLs zu laden (z. B. zum Testen oder Messen der Leistungsauswirkungen einer Codeänderung).

Wenn Sie Beiträge zum Quellcode im öffentlichen GitHub-Repository WindowsAppSDK leisten möchten, sollten Sie Ihre Änderungen testen. Auch dies ist ein Szenario, für das Sie die Umleitung verwenden können, um anstelle der Versionen, die mit dem Windows App SDK geliefert werden, Ihre privaten Kopien von DLLs zu laden.

Ihre Optionen

Es gibt zwei Möglichkeiten, um sicherzustellen, dass Ihre App die von Ihnen gewünschte Version der DLL verwendet:

Tipp

Wenn Sie Entwickler*in oder Administrator*in sind, sollten Sie die DLL-Umleitung für vorhandene Anwendungen verwenden. Das liegt daran, dass keine Änderungen an der App selbst erforderlich sind. Wenn Sie jedoch eine neue App erstellen oder eine vorhandene App aktualisieren und Ihre App von potenziellen Problemen isolieren möchten, erstellen Sie eine parallele Komponente.

Optional: Konfigurieren der Registrierung

Um die DLL-Umleitung computerweit zu aktivieren, müssen Sie einen neuen Registrierungswert erstellen. Erstellen Sie unter dem Schlüssel HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options einen neuen DWORD-Wert mit dem Namen DevOverrideEnable. Legen Sie den Wert auf 1 fest, und starten Sie den Computer neu. Alternativ können Sie den folgenden Befehl verwenden (und den Computer neu starten).

reg add "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Image File Execution Options" /v DevOverrideEnable /t REG_DWORD /d 1

Wenn dieser Registrierungswert festgelegt ist, wird die DotLocal-DLL-Umleitung auch dann berücksichtigt, wenn die App über ein Anwendungsmanifest verfügt.

Erstellen einer Umleitungsdatei oder eine Umleitungsordner

Um die DLL-Umleitung zu verwenden, erstellen Sie wie in späteren Abschnitten dieses Themas beschrieben eine Umleitungsdatei oder einen Umleitungsordner (je nach App-Typ).

Umleiten von DLLs für App-Pakete

Eine gepackte App bzw. ein App-Paket erfordert eine spezielle Ordnerstruktur für die DLL-Umleitung. Am folgenden Pfad sucht das Ladeprogramm, wenn die Umleitung aktiviert ist:

<Drive>:\<path_to_package>\microsoft.system.package.metadata\application.local\

Wenn Sie Ihre .vcxproj-Datei bearbeiten können, können Sie diesen speziellen Ordner bequem erstellen und mit Ihrem Paket bereitstellen, indem Sie dem Build in Ihrer .vcxproj-Datei einige zusätzliche Schritte hinzufügen:

<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>

Sehen wir uns einige der Aktionen an, die bei dieser Konfiguration durchgeführt werden.

  1. Richten Sie ein PreBuildEvent für Ihre Visual Studio-Funktion Ohne Debuggen starten (oder Debuggen starten) ein.

    <ItemDefinitionGroup>
      <PreBuildEvent>
    
  2. Stellen Sie sicher, dass Sie über die richtige Ordnerstruktur in Ihrem Zwischenverzeichnis verfügen.

    <!-- [[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. Kopieren Sie alle DLLs, die Sie lokal erstellt haben (und anstelle der systemseitig bereitgestellten DLLs verwenden möchten) in das Verzeichnis application.local. Sie können DLLs von nahezu allen Speicherorten auswählen (es wird empfohlen, dass Sie die verfügbaren Makros für Ihre .vcxproj-Datei verwenden). Achten Sie einfach darauf, dass diese DLLs vor diesem Projekt erstellt werden. Andernfalls sind sie nicht vorhanden. Hier werden zwei Befehle zum Kopieren von Vorlagen gezeigt. Verwenden Sie beliebig viele dieser Befehle, und bearbeiten Sie die Platzhalter <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. Geben Sie abschließend an, dass Sie das spezielle Verzeichnis und dessen Inhalt in das bereitgestellte Paket einschließen möchten.

    <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>
    

Der hier beschriebene Ansatz (unter Verwendung eines Zwischenverzeichnisses) sorgt dafür, dass Ihre Eintragung für die Quellcodeverwaltung sauber bleibt, und reduziert die Möglichkeit, versehentlich eine kompilierte Binärdatei zu committen.

Als Nächstes müssen Sie lediglich Ihr Projekt (erneut) bereitstellen. Für eine saubere, vollständige Bereitstellung (bzw. erneute Bereitstellung) müssen Sie möglicherweise auch die vorhandene Bereitstellung auf Ihrem Zielgerät deinstallieren/bereinigen.

Manuelles Kopieren der Binärdateien

Wenn Sie Ihre .vcxproj-Datei nicht wie oben beschrieben verwenden können, können Sie stattdessen mit einigen einfachen manuellen Schritten auf Ihrem Zielgerät das gleiche Ziel erreichen.

  1. Bestimmen Sie den Installationsordner des Pakets. Sie können dazu in PowerShell den Befehl Get-AppxPackage ausgeben und nach dem zurückgegebenen InstallLocation-Wert suchen.

  2. Verwenden Sie diesen installLocation, um die Zugriffssteuerungslisten (Access Control List, ACL) zu ändern und sich selbst die Berechtigung zum Erstellen von Ordnern/Kopieren von Dateien zuzuweisen. Bearbeiten Sie die <InstallLocation>-Platzhalter in diesem Skript, und führen Sie das Skript aus:

    cd <InstallLocation>\Microsoft.system.package.metadata
    takeown /F . /A
    icacls  . /grant Administrators:F
    md <InstallLocation>\Microsoft.system.package.metadata\application.local
    
  3. Kopieren Sie zum Schluss alle DLLs, die Sie lokal erstellt haben (und anstelle der systemseitig bereitgestellten DLLs verwenden möchten) manuell in das Verzeichnis application.local, und starten Sie die App neu.

Überprüfen, ob alles funktioniert hat

Um zu sicherzustellen, dass die richtige DLL zur Laufzeit geladen wird, können Sie Visual Studio mit dem angefügten Debugger verwenden.

  1. Öffnen Sie das Fenster Module (Debuggen>Windows>Module).
  2. Suchen Sie nach der DLL, und stellen Sie sicher, dass im Pfad die umgeleitete Kopie und nicht die vom System bereitgestellte Version angegeben ist.
  3. Vergewissern Sie sich, dass nur eine Kopie einer DLL geladen wird.

Umleiten von DLLs für nicht gepackte Apps

Die Umleitungsdatei muss als <your_app_name>.local benannt werden. Wenn der Name Ihrer App Editor.exe lautet, weisen Sie Ihrer Umleitungsdatei also den Namen Editor.exe.local zu. Sie müssen die Umleitungsdatei im Ordner der ausführbaren Datei installieren. Sie müssen auch die DLLs im Ordner der ausführbaren Datei installieren.

Der Inhalt einer Umleitungsdatei wird ignoriert. Sein Vorhandensein allein bewirkt, dass das DLL-Ladeprogramm zuerst den Ordner der ausführbaren Datei überprüft, wenn eine DLL geladen wird. Um das COM-Problem zu beheben, gilt diese Umleitung sowohl für das Laden mit dem vollständigen Pfad als auch das Laden mit einem teilweisen Namen. Die Umleitung erfolgt daher also im COM-Fall und auch unabhängig vom Pfad, der für LoadLibrary oder LoadLibraryEx angegeben ist. Wenn die DLL nicht im Ordner der ausführbaren Datei gefunden wird, wird beim Laden die übliche Suchreihenfolge angewendet. Beispiel: Angenommen, die App C:\myapp\myapp.exe ruft LoadLibrary mit dem folgenden Pfad auf:

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

Sind sowohl C:\myapp\myapp.exe.local als auch C:\myapp\mydll.dll vorhanden, lädt LoadLibrary die Datei C:\myapp\mydll.dll. Andernfalls lädt LoadLibrary die Datei C:\Program Files\Common Files\System\mydll.dll.

Wenn ein Ordner mit dem Namen C:\myapp\myapp.exe.local vorhanden ist und mydll.dll enthält, lädt LoadLibrary stattdessen C:\myapp\myapp.exe.local\mydll.dll.

Wenn Sie die DLL-Umleitung verwenden und die App keinen Zugriff auf alle Laufwerke und Verzeichnisse in der Suchreihenfolge hat, beendet LoadLibrary die Suche, sobald der Zugriff verweigert wird. Wenn Sie die DLL-Umleitung nicht verwenden, überspringt LoadLibrary Verzeichnisse, auf die kein Zugriff besteht, und führt dann die Suche fort.

Es empfiehlt sich, App-DLLs in dem Ordner zu installieren, der die App enthält, auch wenn Sie die DLL-Umleitung nicht verwenden. Dadurch wird sichergestellt, dass durch die Installation der App keine anderen Kopien der DLL überschrieben werden (was zu Fehlern bei anderen Apps führt). Wenn Sie diese bewährte Methode befolgen, wird Ihre Kopie der DLL zudem nicht von anderen Apps überschrieben (und es werden keine damit zusammenhängenden Fehler Ihrer App verursacht).