Partilhar via


Redirecionamento de biblioteca de vínculo dinâmico

O do carregador de DLL é a parte do sistema operacional (SO) que resolve referências a DLLs, carrega-as e as vincula. O redirecionamento de biblioteca de vínculo dinâmico (DLL) é uma das técnicas pelas quais você pode influenciar o comportamento do carregador de DLL e controlar qual das várias DLLs candidatas ele realmente carrega.

Outros nomes para esse recurso incluem .local, Dot Local, DotLocale Dot Local Debugging.

Problemas de versionamento de DLL

Se o seu aplicativo depende de uma versão específica de uma DLL compartilhada e outro aplicativo é instalado com uma versão mais recente ou mais antiga dessa DLL, isso pode causar problemas de compatibilidade e instabilidade; Isso pode fazer com que seu aplicativo comece a falhar.

O carregador de DLL procura na pasta a partir da qual o processo de chamada foi carregado (a pasta do executável) antes de procurar em outros locais do sistema de arquivos. Portanto, uma solução alternativa é instalar a DLL que seu aplicativo precisa na pasta do executável. Isso efetivamente torna a DLL privada.

Mas isso não resolve o problema para a COM. Duas versões incompatíveis de um servidor COM podem ser instaladas e registradas (mesmo em locais diferentes do sistema de arquivos), mas há apenas um lugar para registrar o servidor COM. Assim, apenas o último servidor COM registrado será ativado.

Você pode usar o redirecionamento para resolver esses problemas.

Carregando e testando binários privados

As regras que o carregador de DLL segue garantem que as DLLs do sistema sejam carregadas dos locais do sistema Windows — por exemplo, a pasta do sistema (%SystemRoot%\system32). Essas regras evitam plantar ataques: onde um adversário coloca o código que escreveu em um local no qual pode escrever e, em seguida, convencer algum processo a carregá-lo e executá-lo. Mas as regras do carregador também tornam mais difícil trabalhar em componentes do sistema operacional, porque para executá-los é necessário atualizar o sistema; E essa é uma mudança muito impactante.

Mas você pode usar o redirecionamento para carregar cópias privadas de DLLs (para fins como teste ou medição do impacto no desempenho de uma alteração de código).

Se você quiser contribuir com o código-fonte no repositório público WindowsAppSDK GitHub, então você vai querer testar suas alterações. E, novamente, esse é um cenário para o qual você pode usar o redirecionamento para carregar suas cópias privadas de DLLs em vez das versões fornecidas com o SDK de Aplicativo do Windows.

As suas opções

Na verdade, há duas maneiras de garantir que seu aplicativo use a versão da DLL desejada:

Dica

Se você é um desenvolvedor ou um administrador, então você deve usar o redirecionamento de DLL para aplicativos existentes. Isso porque ele não requer nenhuma alteração no aplicativo em si. Mas se você estiver criando um novo aplicativo ou atualizando um aplicativo existente e quiser isolar seu aplicativo de possíveis problemas, crie um componente lado a lado.

Opcional: configurar o registro

Para habilitar o redirecionamento de DLL em toda a máquina, você deve criar um novo valor do Registro. Sob a chave HKLM\Software\Microsoft\Windows NT\CurrentVersion\Image File Execution Options, crie um novo valor DWORD com o nome DevOverrideEnable. Defina o valor como 1 e reinicie o computador. Ou use o comando abaixo (e reinicie o computador).

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

Com esse valor do Registro definido, o redirecionamento DLL DotLocal é respeitado mesmo se o aplicativo tiver um manifesto do aplicativo.

Criar um arquivo ou pasta de redirecionamento

Para usar o redirecionamento de DLL, você criará um de arquivo de redirecionamento de ou uma pasta de redirecionamento (dependendo do tipo de aplicativo que você tem), como veremos nas seções posteriores deste tópico.

Como redirecionar DLLs para aplicativos empacotados

Um aplicativo empacotado requer uma estrutura de pastas especial para redirecionamento de DLL. O caminho a seguir é onde o carregador olhará quando o redirecionamento estiver habilitado:

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

Se você conseguir editar seu arquivo .vcxproj, uma maneira conveniente de fazer com que essa pasta especial seja criada e implantada com seu pacote é adicionar algumas etapas extras à compilação em seu .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>

Vamos analisar um pouco do que essa configuração faz.

  1. Configure um PreBuildEvent para seu Visual Studio Iniciar sem depurar (ou Iniciar a depuraçãoexperiência ).

    <ItemDefinitionGroup>
      <PreBuildEvent>
    
  2. Verifique se você tem a estrutura de pastas correta em seu diretório intermediário.

    <!-- [[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. Copie todas as DLLs que você criou localmente (e deseja usar em preferência às DLLs implantadas no sistema) para o diretório application.local. Você pode pegar DLLs de praticamente qualquer lugar (recomendamos que você use as macros disponíveis para sua .vcxproj). Apenas certifique-se de que essas DLLs são compiladas antes deste projeto; caso contrário, eles estarão faltando. Dois comandos de modelo cópia são mostrados aqui; Use quantos precisar e edite os espaços reservados <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. Por fim, indique que você deseja incluir o diretório especial e seu conteúdo no pacote implantado.

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

A abordagem descrita aqui (usando um diretório intermediário) mantém o alistamento de controle do código-fonte limpo e reduz a possibilidade de cometer acidentalmente um binário compilado.

Em seguida, tudo o que você precisa fazer é (re)implantar seu projeto. Para obter uma (re)implantação limpa e completa, você também pode ter que desinstalar/limpar a implantação existente no dispositivo de destino.

Copiando os binários manualmente

Se você não é capaz de usar seu .vcxproj da maneira mostrada acima, então você pode alcançar os mesmos fins manualmente em seu dispositivo alvo com alguns passos simples.

  1. Determine a pasta de instalação do pacote. Você pode fazer isso no PowerShell emitindo o comando Get-AppxPackagee procurando o InstallLocation retornado.

  2. Use isso InstallLocation para alterar as ACLs para permitir que você crie pastas/copie arquivos. Edite os espaços reservados <InstallLocation> neste script e execute o script:

    cd <InstallLocation>\Microsoft.system.package.metadata
    takeown /F . /A
    icacls  . /grant Administrators:F
    md <InstallLocation>\Microsoft.system.package.metadata\application.local
    
  3. Por fim, copie manualmente todas as DLLs que você criou localmente (e deseja usar em preferência às DLLs implantadas no sistema) para o diretório application.local e [re]inicie o aplicativo.

Verifique se tudo funcionou

Para confirmar que a DLL correta está sendo carregada no tempo de execução, você pode usar o Visual Studio com o depurador anexado.

  1. Abra a janela Módulos (Debug>Windows>Modules).
  2. Localize a DLL e certifique-se de que a Caminho do indica a cópia redirecionada e não a versão implantada pelo sistema.
  3. Confirme se apenas uma cópia de uma determinada DLL está carregada.

Como redirecionar DLLs para aplicativos não empacotados

O arquivo de redirecionamento deve ser nomeado <your_app_name>.local. Portanto, se o nome do seu aplicativo for Editor.exe, nomeie seu arquivo de redirecionamento Editor.exe.local. Você deve instalar o arquivo de redirecionamento na pasta do executável. Você também deve instalar as DLLs na pasta do executável.

O conteúdo de um arquivo de redirecionamento são ignorados; sua presença por si só faz com que o carregador de DLL verifique a pasta do executável primeiro sempre que ele carrega uma DLL. Para atenuar o problema COM, esse redirecionamento se aplica ao caminho completo e ao carregamento parcial de nomes. Portanto, o redirecionamento acontece no caso COM e também independentemente do caminho especificado para LoadLibrary ou LoadLibraryEx. Se a DLL não for encontrada na pasta do executável, o carregamento seguirá sua ordem de pesquisa habitual. Por exemplo, se o aplicativo C:\myapp\myapp.exe chamar LoadLibrary usando o seguinte caminho:

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

E se C:\myapp\myapp.exe.local e C:\myapp\mydll.dll existirem, LoadLibrary carregará C:\myapp\mydll.dll. Caso contrário, LoadLibrary carrega C:\Program Files\Common Files\System\mydll.dll.

Como alternativa, se uma pasta chamada C:\myapp\myapp.exe.local existir e contiver mydll.dll, LoadLibrary carregará C:\myapp\myapp.exe.local\mydll.dll.

Se você estiver usando o redirecionamento de DLL e o aplicativo não tiver acesso a todas as unidades e diretórios na ordem de pesquisa, LoadLibrary interromperá a pesquisa assim que o acesso for negado. Se você não estiver usando o redirecionamento de DLL, LoadLibrary ignora diretórios que não pode acessar e continua pesquisando.

É uma boa prática instalar DLLs de aplicativo na mesma pasta que contém o aplicativo; mesmo se você não estiver usando o redirecionamento de DLL. Isso garante que a instalação do aplicativo não substitua outras cópias da DLL (fazendo com que outros aplicativos falhem). Além disso, se você seguir essa boa prática, outros aplicativos não substituirão sua cópia da DLL (e não farão com que seu aplicativo falhe).