Executar do Driver Store

Um INF que está usando 'run from Driver Store'significa que o INF usa DIRID 13 para especificar o local para arquivos de pacote de driver na instalação.

Para um arquivo 'run from Driver Store' carregado por um INF, o subdir listado na entrada SourceDisksFiles para o arquivo no INF deve corresponder ao subdir listado na entrada DestinationDirs para o arquivo no INF.

Além disso, uma diretiva CopyFiles não pode ser usada para renomear um arquivo que é executado no Driver Store. 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 Driver Store.

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 'run from Driver Store' que um INF referencia deve ter um nome de arquivo exclusivo.

Localizar e carregar arquivos dinamicamente do Driver Store

Às vezes, há a necessidade de um componente carregar um arquivo que faz parte de um pacote de driver que usa 'run from Driver Store'. Os caminhos para esses arquivos de pacote de driver não devem ser em código, pois 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 surge essa necessidade de carregar arquivos de pacote de driver, esses arquivos de pacote de driver devem ser descobertos e carregados dinamicamente usando alguns dos paradigmas descritos abaixo.

Encontrar 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 possível opção 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á em execução no Driver Store 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 do diretório do qual o driver foi carregado. Como alternativa para drivers que precisam dar suporte a versões do sistema operacional antes do Windows 10 versão 1803, use IoQueryFullDriverPath para encontrar 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 de modo kernel for um driver KMDF, ele poderá usar WdfDriverWdmGetDriverObject para recuperar o objeto do driver WDM para passar para IoQueryFullDriverPath.

Os binários usermode podem usar GetModuleHandleExW e GetModuleFileNameW para determinar de onde o driver foi carregado. Por exemplo, um binário de driver UMDF pode fazer algo parecido com o seguinte:

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

Encontrar 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 for preferencial 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 para se comunicar com um driver no pacote de driver.
  • Um pacote de driver de extensão contém um arquivo de configuração que é carregado pelo driver no pacote de driver base.

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

Um pacote de driver normalmente usaria um AddReg HKR para definir esse estado. Para este exemplo, deve-se assumir que, para , o pacote de driver tem uma entrada ExampleFile.dllExampleFile.dll sem subdir. Isso faz com que o arquivo está na raiz do diretório do pacote de driver. Também deve ser presumido que a diretiva 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 o 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 de sinalizadores vazio, o que resulta em um REG_SZ do Registro. Isso resulta no %13% sendo transformado em um caminho de arquivo de 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 %13% será convertido em um caminho com variáveis de ambiente apropriadas para abstrair o local do caminho. Ao recuperar esse valor do Registro, chame ExpandEnvironmentStrings para resolver as variáveis de ambiente no caminho.

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

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 de modo de usuário 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, pesquise o dispositivo apropriado antes de ler o estado do dispositivo. Por exemplo, chame CM_Get_DevNode_Property para recuperar propriedades no dispositivo ao procurar um dispositivo que corresponde a critérios específicos.

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

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

Para acessar essa configuração quando for 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 do dispositivo usadas nas APIs acima. Examine essas interfaces para determinar qual é a interface correta para a configuração a ser lida.

Depois que a interface do 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 se registrar para notificações de interface do dispositivo na classe de interface do 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 do dispositivo usadas nas APIs acima. Examine essas interfaces para determinar qual é a interface correta que deve ter a configuração a ser lida.

Depois que o nome do link simbólico apropriado for encontrado, chame IoOpenDeviceInterfaceRegistryKey para recuperar um handle para o local do Registro em que 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 eCM_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 driver

Por padrão, um pacote de driver não poderá ser removido do sistema se ele ainda estiver instalado em qualquer dispositivo. No entanto, algumas opções para remover um pacote de driver do sistema permitem que ele seja tentado a ser removido "force". Isso tentará remover o pacote de driver mesmo que esse pacote de driver ainda esteja instalado em alguns dispositivos no sistema. Remoção de força não são permitidas para pacotes de driver que têm arquivos que são 'executados do Driver Store'. Quando um pacote de driver é removido do sistema, seu conteúdo do Driver Store é removido. Se houver dispositivos que ainda estão instalados com esse pacote de driver, todos os arquivos 'run from Driver Store' nesse pacote de driver agora terão sido perdidos e esses arquivos ausentes poderão causar um problema no dispositivo. Para evitar colocar o dispositivo em um estado ruim como esse, os pacotes de driver que contêm qualquer arquivo 'run from Driver Store' não podem ser removidos à força. Eles só podem ser removidos depois que não estão mais instalados em nenhum dispositivo. Para auxiliar nas remoções desses pacotes de driver, diUninstallDriver ou pnputil /delete-driver oem#.inf /uninstall pode ser usado. Esses métodos de remoção atualizarão primeiro todos os dispositivos que usam o pacote de driver que está sendo removido para não serem mais instalados com esse pacote de driver antes de tentar remover o pacote de driver.

Desenvolvimento de pacote de driver

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 recriar totalmente e substituir 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 Driver Store não deve ser em código, é 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 isso (e outros cenários), os nomes de arquivos em pacotes de driver devem ser tão exclusivos quanto possível para que ele não corresponder ao nome de um arquivo de um pacote de driver não relacionado no sistema.