Executar do Repositório de Drivers

Um INF que esteja usando "executar do Repositório de Drivers' significa que o INF usa DIRID 13 para especificar o local para os arquivos do pacote de driver na instalação.

Para um arquivo de "executar do Repositório de Drivers" carregado por um INF, o subdiretório listado na entrada SourceDisksFiles para o arquivo no INF deve corresponder ao subdiretório listado na entrada DestinationDirs do arquivo no INF.

Além disso, uma diretiva CopyFiles não pode ser usada para renomear um arquivo executado do Repositório de Drivers. Essas restrições são necessárias para que a instalação de um INF em um dispositivo não resulte na criação de novos arquivos no diretório do Repositório de Drivers.

Como as entradas SourceDisksFiles não podem ter várias entradas com o mesmo nome de arquivo e CopyFiles não podem ser usadas para renomear um arquivo, cada arquivo de "executar do Repositório de Drivers" a que um INF faz referência deve ter um nome de arquivo exclusivo.

Os pacotes de driver têm suporte geral para "executar do Repositório de Drivers" a partir do Windows 10 1709. No entanto, certas pilhas de dispositivos podem colocar restrições extras em arquivos que você precisa para fornecer esse plug -in para essa pilha. Alguns exemplos são essas pilhas de dispositivos que não davam suporte a "executar do Repositório de Drivers" até o Windows 10 1803:

Se fornecer um binário que se conecta a uma pilha de dispositivo específica, consulte a documentação da pilha de dispositivos específica à qual você está conectando para verificar se ela oferece suporte ao fornecimento de um caminho de arquivo completo para o binário e se há alguma restrição nesse caminho de arquivo completo. Se ele dá suporte ao fornecimento de um caminho de arquivo completo para o binário sem restrições sobre esse caminho, então ele deve dar suporte ao arquivo que está sendo "executado do Repositório de Drivers".

Localização e carregamento dinâmicos de arquivos do Repositório de Drivers

Às vezes, há a necessidade de um componente carregar um arquivo que faz parte de um pacote de driver que usa "executar do Repositório de Drivers". Os caminhos para esses arquivos de pacote de driver não devem ser codificados, pois eles podem ser diferentes entre diferentes versões do pacote de driver, diferentes versões do sistema operacional, diferentes edições do sistema operacional etc. Quando tal necessidade de carregar arquivos de pacote de driver surge, esses arquivos de pacote de driver devem ser descobertos e carregados dinamicamente usando alguns dos paradigmas descritos abaixo.

Localizar e carregar arquivos no mesmo pacote de driver

Quando um arquivo em um pacote de driver precisa carregar outro arquivo do mesmo pacote de driver, uma opção potencial para descobrir dinamicamente esse arquivo é determinar o diretório do qual esse arquivo está sendo executado e carregar o outro arquivo relativo a esse diretório.

Um driver WDM ou KMDF que está sendo executado do Repositório de Drivers no Windows 10 versão 1803 e posterior que precisa acessar outros arquivos de seu pacote de driver deve chamar IoGetDriverDirectory com DriverDirectoryImage como o tipo de diretório para obter o caminho de diretório do qual o driver foi carregado. Como alternativa, para drivers que precisam oferecer suporte a versões do sistema operacional anteriores ao Windows 10 versão 1803, use IoQueryFullDriverPath para localizar o caminho do driver, obter o caminho do diretório do qual ele foi carregado e procurar arquivos relativos a esse caminho. Se o driver do modo kernel for um driver KMDF, ele poderá usar WdfDriverWdmGetDriverObject para recuperar o objeto de driver WDM a ser passado para IoQueryFullDriverPath.

Os binários do modo de usuário podem usar GetModuleHandleExW eGetModuleFileNameW para determinar de onde o binário foi carregado. Por exemplo, um binário do driver UMDF pode fazer algo como o seguinte:

bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
                         (PCWSTR)&DriverEntry,
                         &handleModule);
if (bRet) {
    charsWritten = GetModuleFileNameW(handleModule,
                                      path,
                                      pathLength);
    …

Localizar e carregar arquivos em qualquer pacote de driver

Em alguns cenários, um pacote de driver pode conter um arquivo que se destina a ser carregado por um binário em outro pacote de driver ou por um componente de modo de usuário. Esse método também pode ser usado para arquivos do mesmo pacote de driver se isso for preferido em vez do método descrito acima para carregar arquivos do mesmo pacote de driver.

Aqui estão alguns exemplos de cenários que podem envolver o carregamento de arquivos de um pacote de driver:

  • Uma DLL de modo de usuário em um pacote de driver fornece uma interface de comunicação com um driver no pacote de driver.

  • Um pacote do driver de expansão contém um arquivo de configuração que é carregado pelo driver no pacote de driver de base.

Nessas situações, o pacote do driver deve definir algum estado em um dispositivo ou interface de dispositivo que indica o caminho do arquivo a ser carregado.

Um pacote de driver normalmente usaria um AddReg de HKR para definir esse estado. Para este exemplo, deve-se assumir que, para ExampleFile.dll, o pacote de driver tem uma entrada SourceDisksFiles sem subdir. Isso faz com que o arquivo esteja na raiz do diretório do pacote de driver. Também deve ser considerado que o DestinationDirs para uma diretiva CopyFiles especifica dirid 13.

Aqui está um exemplo de INF para definir isso como estado do dispositivo:

[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg

[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

Um exemplo de INF para definir isso como estado da interface do dispositivo seria:

[ExampleDDInstall.Interfaces]
AddInterface = {<fill in an interface class GUID for an interface exposed by the device>},,Example_Add_Interface_Section

[Example_Add_Interface_Section]
AddReg = Example_Add_Interface_Section.AddReg

[Example_Add_Interface_Section.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll

Os exemplos anteriores usam um valor vazio de sinalizadores, que resulta em um valor de registro REG_SZ. Isso faz com que %13% se transforme em um caminho de arquivo do modo de usuário totalmente qualificado. Em muitos casos, é preferível que o caminho seja relativo a uma variável de ambiente. Se um valor de sinalizadores de 0x20000 for usado, o valor do registro será do tipo REG_EXPAND_SZ, e o %13% será convertido em um caminho com variáveis de ambiente apropriadas para abstrair o local do caminho. Ao trazer esse valor do registro, chame ExpandEnvironmentStrings para resolver as variáveis de ambiente no caminho.

Se o valor precisar ser lido por um componente do modo kernel, o valor deverá ser um valor REG_SZ. Quando o componente do modo kernel lê esse valor, ele deve preceder \??\ antes de passá-lo para APIs como ZwOpenFile.

Para acessar essa configuração quando ela faz parte do estado do dispositivo, primeiro o aplicativo deve encontrar a identidade do dispositivo. O código do modo de usuário pode usar CM_Get_Device_ID_List_Size e CM_Get_Device_ID_List para obter uma lista de dispositivos, filtrados conforme necessário. Essa lista de dispositivos pode conter vários dispositivos, portanto, procure o dispositivo apropriado antes de ler o estado do dispositivo. Por exemplo, chame CM_Get_DevNode_Property para trazer propriedades no dispositivo ao procurar um dispositivo que corresponda a critérios específicos.

Depois que o dispositivo correto for encontrado, chame CM_Open_DevNode_Key para obter um identificador para o local do registro em que o estado do dispositivo foi armazenado.

O código do modo kernel deve trazer um objeto de dispositivo físico (PDO) para o dispositivo com o estado e chamar IoOpenDeviceRegistryKey. Uma maneira possível para o código do modo kernel recuperar o PDO do dispositivo é descobrir uma interface habilitada exposta pelo dispositivo e usar IoGetDeviceObjectPointer para trazer o objeto de dispositivo.

Para acessar essa configuração quando o estado da interface do dispositivo, o código do modo de usuário pode chamar CM_Get_Device_Interface_List_Size e CM_Get_Device_Interface_List.

Além disso, CM_Register_Notification pode ser usado para ser notificado sobre chegadas e remoções de interfaces de dispositivo para que o código seja notificado quando a interface estiver habilitada e, em seguida, possa recuperar o estado. Pode haver várias interfaces de dispositivo na classe de interface de dispositivo usada nas APIs acima. Examine essas interfaces para determinar qual é a interface correta para a configuração a ser lida.

Quando a interface de dispositivo correta for encontrada, chame CM_Open_Device_Interface_Key.

O código do modo kernel pode recuperar um nome de link simbólico para a interface do dispositivo da qual obter o estado. Para fazer isso, chame IoRegisterPlugPlayNotification para registrar notificações de interface de dispositivo na classe de interface de dispositivo apropriada. Como alternativa, chame IoGetDeviceInterfaces para obter uma lista de interfaces de dispositivo atuais no sistema. Pode haver várias interfaces de dispositivo na classe de interface de dispositivo usada nas APIs acima. Examine essas interfaces para determinar qual é a interface correta que deve ter a configuração a ser lida.

Quando o nome de link simbólico apropriado for encontrado, chame IoOpenDeviceInterfaceRegistryKey para recuperar um identificador para o local do registro onde o estado da interface do dispositivo foi armazenado.

Observação

Use o sinalizador CM_GETIDLIST_FILTER_PRESENT com CM_Get_Device_ID_List_Size e CM_Get_Device_ID_List ou o sinalizador CM_GET_DEVICE_INTERFACE_LIST_PRESENT com CM_Get_Device_Interface_List_Size e CM_Get_Device_Interface_List. Isso garante que o hardware relacionado ao estado que contém o caminho do arquivo esteja presente e pronto para comunicação.

Removendo o pacote de drivers

Por padrão, um pacote de driver não pode ser removido do sistema se ainda estiver instalado em qualquer dispositivo. No entanto, algumas opções para remover um pacote de driver do sistema permitem que ele seja tentado para ser removido "forçadamente". Isso tenta remover o pacote de driver mesmo se esse pacote de driver ainda estiver instalado em alguns dispositivos no sistema. As remoções forçadas não são permitidas para pacotes de driver que tenham arquivos que sejam "executados do Repositório de Drivers". Quando um pacote de driver é removido do sistema, seu conteúdo do Repositório de Drivers é removido. Se houver dispositivos que ainda estão instalados com esse pacote de driver, todos os arquivos "executados do Repositório de Drivers" nesse pacote de driver desaparecerão e esses arquivos ausentes podem causar o mau funcionamento desse dispositivo. Para evitar colocar o dispositivo em um estado ruim como esse, os pacotes de driver que contêm quaisquer arquivos de "executar do Repositório de Drivers" não podem ser removidos à força. Eles só podem ser removidos quando não estiverem mais instalados em nenhum dispositivo. Para ajudar nas remoções de tais pacotes de driver, DiUninstallDriver ou pnputil /delete-driver <oem#.inf> /uninstall podem ser usados. Esses métodos de remoção primeiro atualizarão todos os dispositivos que usam o pacote de driver que está sendo removido para não ser mais instalado com esse pacote de driver antes de tentar remover o pacote de driver.

Desenvolvimento de pacotes de drivers

Testando binários privados

Ao desenvolver um pacote de driver, se houver a necessidade de substituir um arquivo executável específico do pacote de driver por uma versão privada em vez de reconstruir e substituir totalmente o pacote de driver no sistema, é recomendável que um depurador de kernel seja usado junto com o comando .kdfiles. Como o caminho completo para o arquivo no Repositório de Drivers não deve ser codificado, é recomendável que, no mapeamento .kdfiles, o nome do arquivo OldDriver seja apenas o nome direto do arquivo sem informações de caminho anteriores. Para facilitar esse (e outros cenários), os nomes de arquivos em pacotes de driver devem ser o mais exclusivos possível para que não correspondam ao nome de um arquivo de um pacote de driver não relacionado no sistema.

Portando um INF para usar executado a partir do Repositório de Drivers

Se você tiver um pacote de driver existente com um INF que não usa executar do Repositório de Drivers e estiver fazendo a portabilidade para usar executar do Repositório de Drivers, os exemplos a seguir mostram alguns usos comuns de arquivos em INFs e padrões na atualização desses arquivos a serem executados desde o Repositório de Drivers.

Referência rápida para atualizações do diretório de destino

A tabela a seguir fornece uma referência rápida para localizar a orientação apropriada com base no DIRID do diretório de destino atual que um pacote de driver INF especifica para um arquivo.

DIRID Subdiretório Detalhes
13 O arquivo já está usando "executar do Repositório de Drivers". Nenhum outro trabalho é necessário.
1 DIRID 1 não deverá ser usado. Não há garantia de que o diretório de origem estará disponível quando uma referência ao arquivo precisar ser resolvida. Em vez disso, se os componentes no pacote do driver dependerem de arquivos específicos, inclua esses arquivos no pacote do driver e execute a partir do Repositório de Drivers.
10 Firmware Para saber mais sobre como usar o DIRID 13 com um pacote de driver de atualização de firmware para fazê-lo usar "executar a partir do Repositório de Drivers", consulte Como criar um pacote de driver de atualização.
10 Consulte Outros arquivos.
11 Consulte Outros arquivos.
12 UMDF Consulte Binário do driver UMDF.
12 A maioria dos arquivos com um destino de DIRID 12 representam binários de serviço de driver. Consulte Binário de serviço.
16422, 16426, 16427, 16428 A maioria dos arquivos com um destino desses DIRIDs representa a instalação de um aplicativo. Em vez disso, forneça um aplicativo da Plataforma Universal do Windows (UWP) e instale-o usando uma diretiva AddSoftware de uma seção DDInstall.Software do pacote de driver INF. Para obter detalhes, consulte Emparelhando um driver com um aplicativo da UWP (Plataforma Universal do Windows).

Binário de serviço

Se o INF adicionar um serviço e o binário não for executado a partir do Repositório de Drivers, seu INF poderá ter a seguinte aparência:

[DestinationDirs]
 ; Copy the file to %windir%\system32\drivers
 Example_CopyFiles = 12

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the file in %windir%\system32\drivers
ServiceBinary = %12%\ExampleBinary.sys

Para mover esse arquivo a ser executado do Repositório de Drivers, você precisaria atualizar a entrada DestinationDirs para onde o arquivo será copiado e atualizar a diretiva ServiceBinary fazendo referência ao local desse arquivo.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleBinary.sys

[ExampleDDInstall.Services]
AddService = ExampleService,0x2,Example_Service_Inst

[Example_Service_Inst]
DisplayName   = %SvcDesc%
ServiceType   = %SERVICE_KERNEL_DRIVER%
StartType     = %SERVICE_DEMAND_START%
ErrorControl  = %SERVICE_ERROR_NORMAL%
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleBinary.sys

Binário do driver UMDF

Se o INF adicionar um driver UMDF e o binário não for executado a partir do Repositório de Drivers, seu INF poderá ter a seguinte aparência:

[DestinationDirs]
; Copy the file to %windir%\system32\drivers\UMDF
Example_CopyFiles = 12, UMDF

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the file in %windir%\system32\drivers\UMDF
ServiceBinary = %12%\UMDF\ExampleUmdfDriver.dll
...

Para mover esse arquivo a ser executado do Repositório de Drivers, você precisaria atualizar a entrada DestinationDirs para onde o arquivo será copiado e atualizar a diretiva ServiceBinary fazendo referência ao local desse arquivo.

[DestinationDirs]
; Update the destination to DIRID 13
Example_CopyFiles = 13

[ExampleDDInstall]
CopyFiles = Example_CopyFiles

[Example_CopyFiles]
ExampleUmdfDriver.dll

[ExampleDDInstall.Wdf]
UmdfService = ExampleUmdfDriver,Example_UMDF_Inst
...

[Example_UMDF_Inst]
; Point at the run from Driver Store file using DIRID 13
ServiceBinary = %13%\ExampleUmdfDriver.dll
...

Outros arquivos

Se o INF adicionar um arquivo que pode ser carregado por outros componentes e não for executado do Repositório de Drivers, o INF poderá ter a seguinte aparência. Neste exemplo, somente o nome do arquivo é gravado no estado do registro do dispositivo. Os componentes que leem esse valor do Registro para determinar qual arquivo carregar dependeriam do arquivo que está em %windir%\system32 ou dependeriam da ordem de pesquisa da LoadLibrary para encontrar o arquivo.

[DestinationDirs]
; Copy the file to %windir%\system32
Example_CopyFiles = 11

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
HKR,,FileLocation,,"ExampleFile.dll"

Para mover esse arquivo a ser executado do Repositório de Drivers, você precisaria atualizar a entrada DestinationDirs para onde o arquivo será copiado e atualizar o local salvo no estado do dispositivo. Isso requer que os componentes que leem esse valor do registro consigam manipulá0-lo sendo o caminho completo para um arquivo em vez de um arquivo relativo a %windir%\system32.

[DestinationDirs]
Example_CopyFiles = 13 ; update the destination to DIRID 13

[ExampleDDInstall]
CopyFiles=Example_CopyFiles
AddReg=Example_AddReg

[Example_CopyFiles]
ExampleFile.dll

[Example_AddReg]
; Point at the run from Driver Store file using DIRID 13
HKR,,FileLocation,,"%13%\ExampleFile.dll"