Reindirizzamento della libreria a collegamento dinamico

Il caricatore DLL fa parte del sistema operativo che risolve i riferimenti alle DLL, li carica e li collega. Il reindirizzamento della libreria a collegamento dinamico (DLL) è una delle tecniche con cui è possibile influenzare il comportamento del caricatore dll e controllare quale delle DLL candidate carica effettivamente.

Altri nomi per questa funzionalità includono .local, Dot Local, DotLocal e Dot Local Debugging.

Problemi di controllo delle versioni delle DLL

Se l'applicazione dipende da una versione specifica di una DLL condivisa e un'altra applicazione viene installata con una versione più recente o precedente di tale DLL, ciò può causare problemi di compatibilità e instabilità; può causare l'esito negativo dell'avvio dell'app.

Il caricatore DLL cerca nella cartella da cui è stato caricato il processo chiamante (la cartella dell'eseguibile) prima di eseguire l'ricerca in altri percorsi del file system. Una soluzione alternativa consiste quindi nell'installare la DLL necessaria per l'app nella cartella del file eseguibile. Ciò rende effettivamente privata la DLL.

Ma questo non risolve il problema per COM. È possibile installare e registrare due versioni incompatibili di un server COM (anche in percorsi di file system diversi), ma esiste solo una posizione in cui registrare il server COM. Verrà quindi attivato solo il server COM registrato più recente.

È possibile usare il reindirizzamento per risolvere questi problemi.

Caricamento e test di file binari privati

Le regole che seguono il caricatore DLL assicurano che le DLL di sistema vengano caricate dai percorsi di sistema di Windows, ad esempio la cartella di sistema (%SystemRoot%\system32). Queste regole evitano attacchi di impianto: dove un antagonista inserisce il codice scritto in una posizione in cui possono scrivere e quindi convincere un processo a caricarlo ed eseguirlo. Ma le regole del caricatore rendono anche più difficile lavorare sui componenti del sistema operativo, perché per eseguirli richiede l'aggiornamento del sistema; ed è un cambiamento molto significativo.

Tuttavia, è possibile usare il reindirizzamento per caricare copie private di DLL (a scopo di test o misurazione dell'impatto sulle prestazioni di una modifica del codice).

Se vuoi contribuire al codice sorgente nel repository GitHub pubblico di WindowsAppSDK , dovrai testare le modifiche. Anche in questo caso, si tratta di uno scenario per il quale è possibile usare il reindirizzamento per caricare le copie private di DLL invece delle versioni fornite con il SDK per app di Windows.

Opzioni disponibili

Esistono infatti due modi per assicurarsi che l'app usi la versione della DLL che vuoi:

  • Reindirizzamento DLL. Continuare a leggere questo argomento per altri dettagli.
  • Componenti affiancati. Descritto nell'argomento Applicazioni isolate e assembly side-by-side.

Suggerimento

Gli sviluppatori o gli amministratori devono usare il reindirizzamento DLL per le applicazioni esistenti. Questo perché non richiede modifiche all'app stessa. Tuttavia, se stai creando una nuova app o aggiornando un'app esistente e vuoi isolare l'app da potenziali problemi, crea un componente affiancato.

Facoltativo: configurare il Registro di sistema

Per abilitare il reindirizzamento dll a livello di computer, è necessario creare un nuovo valore del Registro di sistema. Nella chiave HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Optionscreare un nuovo valore DWORD con il nome DevOverrideEnable. Impostare il valore su 1 e riavviare il computer. In alternativa, usare il comando seguente (e riavviare il computer).

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

Con il valore del Registro di sistema impostato, il reindirizzamento della DLL DotLocal viene rispettato anche se l'app ha un manifesto dell'applicazione.

Creare un file o una cartella di reindirizzamento

Per usare il reindirizzamento dll, creerai un file di reindirizzamento o una cartella di reindirizzamento (a seconda del tipo di app disponibile), come vedremo nelle sezioni successive di questo argomento.

Come reindirizzare le DLL per le app in pacchetto

Un'app in pacchetto richiede una struttura di cartelle speciale per il reindirizzamento dll. Il percorso seguente è il percorso in cui il caricatore cercherà quando il reindirizzamento è abilitato:

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

Se si è in grado di modificare il .vcxproj file, un modo pratico per creare e distribuire la cartella speciale con il pacchetto consiste nell'aggiungere alcuni passaggi aggiuntivi alla compilazione .vcxprojin :

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

Verranno ora illustrate alcune delle operazioni di questa configurazione.

  1. Configurare un PreBuildEvent oggetto per l'esperienza Di avvio senza debug di Visual Studio (o Avvia debug).

    <ItemDefinitionGroup>
      <PreBuildEvent>
    
  2. Assicurarsi di avere la struttura di cartelle corretta nella directory intermedia.

    <!-- [[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. Copiare tutte le DLL compilate in locale (e si vuole usare in preferenza per le DLL distribuite dal sistema) nella application.local directory. È possibile raccogliere DLL da qualsiasi posizione (è consigliabile usare le macro disponibili per il proprio )..vcxproj Assicurarsi che tali DLL vengano compilate prima che questo progetto funzioni; altrimenti mancheranno. Di seguito sono visualizzati due comandi di copia del modello . Usare il numero necessario e modificare i <path-to-local-dll> segnaposto.

      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. Infine, indicare che si vuole includere la directory speciale e il relativo contenuto nel pacchetto distribuito.

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

L'approccio descritto qui (usando una directory intermedia) mantiene il controllo del codice sorgente pulito e riduce la possibilità di eseguire accidentalmente il commit di un file binario compilato.

A questo punto, è sufficiente (ri)distribuire il progetto. Per ottenere una distribuzione completa e pulita, potrebbe anche essere necessario disinstallare/pulire la distribuzione esistente nel dispositivo di destinazione.

Copia manuale dei file binari

Se non sei in grado di usare il tuo .vcxproj nel modo illustrato sopra, puoi ottenere le stesse estremità a mano sul dispositivo di destinazione con un paio di semplici passaggi.

  1. Determinare la cartella di installazione del pacchetto. È possibile eseguire questa operazione in PowerShell eseguendo il comando Get-AppxPackagee cercando InstallLocation restituito.

  2. Usare installLocation per modificare gli elenchi di controllo di accesso per consentire a se stessi di creare cartelle/copiare file. Modificare i <InstallLocation> segnaposto in questo script ed eseguire lo script:

    cd <InstallLocation>\Microsoft.system.package.metadata
    takeown /F . /A
    icacls  . /grant Administrators:F
    md <InstallLocation>\Microsoft.system.package.metadata\application.local
    
  3. Infine, copiare manualmente tutte le DLL compilate in locale (e si vogliono usare in preferenza per le DLL distribuite dal sistema) nella application.local directory e [ri]avviare l'app.

Verificare che tutto funzioni

Per verificare che la DLL corretta venga caricata in fase di esecuzione, è possibile usare Visual Studio con il debugger collegato.

  1. Aprire la finestra Moduli (Debug>di moduli Windows).>
  2. Trovare la DLL e assicurarsi che il percorso indichi la copia reindirizzata e non la versione distribuita dal sistema.
  3. Verificare che venga caricata una sola copia di una determinata DLL.

Come reindirizzare le DLL per le app non in pacchetto

Il file di reindirizzamento deve essere denominato <your_app_name>.local. Quindi, se il nome dell'app è Editor.exe, assegnare al file Editor.exe.localdi reindirizzamento il nome . È necessario installare il file di reindirizzamento nella cartella dell'eseguibile. È anche necessario installare le DLL nella cartella dell'eseguibile.

Il contenuto di un file di reindirizzamento viene ignorato. La sua presenza fa sì che il caricatore DLL controlli prima la cartella dell'eseguibile ogni volta che carica una DLL. Per attenuare il problema COM, il reindirizzamento si applica sia al percorso completo che al caricamento parziale dei nomi. Quindi il reindirizzamento avviene nel caso COM e anche indipendentemente dal percorso specificato per LoadLibrary o LoadLibraryEx. Se la DLL non viene trovata nella cartella dell'eseguibile, il caricamento segue il consueto ordine di ricerca. Ad esempio, se l'app C:\myapp\myapp.exe chiama LoadLibrary usando il percorso seguente:

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

E se esistono e C:\myapp\myapp.exe.localC:\myapp\mydll.dll , LoadLibrary carica .C:\myapp\mydll.dll In caso contrario, LoadLibrary carica C:\Program Files\Common Files\System\mydll.dll.

In alternativa, se esiste una cartella denominata C:\myapp\myapp.exe.local e contiene mydll.dll, LoadLibrary carica C:\myapp\myapp.exe.local\mydll.dll.

Se si usa il reindirizzamento dll e l'app non ha accesso a tutte le unità e le directory nell'ordine di ricerca, LoadLibrary interrompe la ricerca non appena viene negato l'accesso. Se non si usa il reindirizzamento DLL, LoadLibrary ignora le directory a cui non è possibile accedere e quindi continua la ricerca.

È consigliabile installare dll dell'app nella stessa cartella che contiene l'app; anche se non si usa il reindirizzamento dll. Ciò garantisce che l'installazione dell'app non sovrascriva altre copie della DLL (causando l'esito negativo di altre app). Inoltre, se si segue questa procedura consigliata, le altre app non sovrascrivono la copia della DLL e non causano l'esito negativo dell'app.