Partilhar via


Executar a partir do repositório de drivers

Um INF que está usando 'executar a partir de Driver Store' significa que o INF usa DIRID 13 para especificar o local para arquivos de pacote de driver durante a 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 a partir do 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 Driver Store.

Como as entradas SourceDisksFiles não podem ter várias entradas com o mesmo nome de arquivo e CopyFiles não pode ser usado para renomear um arquivo, cada arquivo 'executar do Driver Store' que um INF referencia deve ter um nome de arquivo exclusivo.

Os pacotes de drivers têm suporte geral para 'executar a partir da Loja de Drivers' a partir do Windows 10 1709. No entanto, certos stacks de dispositivos podem impor restrições adicionais a ficheiros que é necessário fornecer para integrar nessa stack. Alguns exemplos são estas pilhas de dispositivos que não suportavam 'executar a partir da Loja de Drivers' até ao Windows 10 1803:

Se fornecer um binário que se conecta a uma pilha de dispositivos específica, consulte a documentação da pilha de dispositivos específica à qual você está se conectando para verificar se ela suporta o fornecimento de um caminho de arquivo completo para o binário e se há alguma restrição nesse caminho de arquivo completo. Se houver suporte para fornecer um caminho de ficheiro completo para o binário sem restrições nesse caminho, então deve suportar a execução do ficheiro a partir do 'Driver Store'.

Localizando e carregando arquivos dinamicamente do Driver Store

Às vezes, é necessário que um componente carregue um ficheiro que faz parte de um pacote de drivers que utiliza a opção 'executar a partir da loja de drivers'. Os caminhos para esses arquivos de pacote de driver não devem ser codificados, 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.

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 a partir 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 a partir do 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 de diretório do qual o driver foi carregado. Como alternativa, para drivers que precisam suportar 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 a partir 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 do driver WDM para passar para IoQueryFullDriverPath.

Os binários do modo de usuário podem usar GetModuleHandleExW e GetModuleFileNameW para determinar de onde o binário foi carregado. Por exemplo, um binário de 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. Este método também pode ser usado para arquivos do mesmo pacote de driver, se isso for preferido sobre o 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 utilizador num pacote de drivers fornece uma interface para comunicação com um driver no pacote de drivers.

  • 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 se espera que seja carregado.

Um pacote de driver normalmente usaria um AddReg HKR para definir esse estado. Para este exemplo, deve-se supor 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 assumido 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 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 de sinalizadores vazios, que resulta em um valor de registro REG_SZ. 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 flags de 0x20000 for usado, o valor do registo será do tipo REG_EXPAND_SZ e o %13% será convertido num caminho com variáveis de ambiente apropriadas para tornar a localização do caminho abstrata. Ao recuperar esse valor do Registro, chame ExpandEnvironmentStrings para resolver as variáveis de ambiente no caminho.

Se o valor precisa ser lido por um componente de modo kernel, o valor deve 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 recuperar propriedades no dispositivo ao procurar um dispositivo que corresponda a critérios específicos.

Quando o dispositivo correto for encontrado, chame CM_Open_DevNode_Key para obter um identificador para o local do registro onde 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 do 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 aceder a esta configuração quando estiver no estado da interface do dispositivo, o código em modo de utilizador pode chamar CM_Get_Device_Interface_List_Size e CM_Get_Device_Interface_List.

Além disso, CM_Register_Notification pode ser usado para notificar sobre a chegada e remoção de interfaces de dispositivos, assim o código é informado quando a interface é ativada e pode então 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 leitura da configuração.

Quando a interface correta do dispositivo 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 a partir do qual obter o estado. Para fazer isso, chame IoRegisterPlugPlayNotification para se registrar para 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 lida.

Quando o nome do 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 driver

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 a ser removido à força. Isso tenta remover o pacote de driver mesmo se esse pacote de driver ainda estiver instalado em alguns dispositivos no sistema. A remoção forçada não é permitida para pacotes de controladores que tenham ficheiros que são 'executados a partir do Driver Store'. Quando um pacote de driver é removido do sistema, o seu conteúdo do Armazenamento de Drivers é removido. Se houver algum dispositivo que ainda esteja instalado com esse pacote de driver, qualquer arquivo 'executar a partir do Driver Store' nesse pacote de driver será removido e esses arquivos ausentes podem causar o mau funcionamento do dispositivo. Para evitar colocar o dispositivo em um estado ruim como esse, os pacotes de driver que contêm qualquer arquivo 'executar a partir da Loja de Driver' não podem ser removidos à força. Eles só podem ser removidos quando não estiverem mais instalados em nenhum dispositivo. Para ajudar na remoção de tais pacotes de driver, DiUninstallDriver ou pnputil /delete-driver <oem#.inf> /uninstall pode ser usado. Esses métodos de remoção primeiro atualizarão todos os dispositivos usando 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 totalmente e substituir o pacote de driver no sistema, é recomendável que um depurador do kernel seja usado junto com o comando .kdfiles . Como o caminho completo para o arquivo no Driver Store 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 isso (e outros cenários), os nomes dos 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.

Adaptar um INF para ser executado a partir do Driver Store

Se tiveres um pacote de driver existente com um INF que não usa executar a partir da Driver Store e estiveres a migrar para usar executar a partir da Driver Store, os exemplos a seguir mostram alguns usos comuns de arquivos em INFs e padrões na atualização desses arquivos para serem executados a partir da Driver Store.

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

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

DIRID Subdiretório Detalhes
13 O ficheiro já está a utilizar 'executar a partir da Loja de Controladores'. Não é necessário mais trabalho.
1 DIRID 1 não deve ser utilizado. 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 de driver dependerem de arquivos específicos, inclua esses arquivos no pacote de driver e execute-os a partir do Driver Store.
10 firmware Para obter informações sobre como usar o DIRID 13 com um pacote de driver de atualização de firmware para que utilize 'executar a partir do Driver Store', consulte Criação de um pacote de driver de atualização para mais informações.
10 Consulte Outros ficheiros.
11 Consulte Outros ficheiros.
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 representam 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 Emparelhar um driver com um aplicativo da Plataforma Universal do Windows (UWP).

Serviço binário

Se o seu INF adicionar um serviço e o binário não for executado a partir do Driver Store, então o seu INF pode 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 para ser executado do Driver Store, 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 seu INF adicionar um driver UMDF e o binário não for executado a partir do Driver Store, então o INF pode assemelhar-se a:

[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 para ser executado do Driver Store, 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 ficheiros

Se o seu INF adicionar um ficheiro que pode ser carregado por outros componentes e não for executado a partir do Armazenamento de Controladores, então o seu INF poderá ter a seguinte aparência. Neste exemplo, apenas o nome do arquivo é gravado no estado do registro do dispositivo. Os componentes que leem este valor do registo para determinar qual ficheiro carregar dependeriam de o ficheiro estar em %windir%\system32 ou dependeriam da ordem de pesquisa do LoadLibrary ser capaz de localizar o ficheiro.

[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 para ser executado a partir do Driver Store, você precisa atualizar a entrada DestinationDirs para onde o arquivo será copiado e atualizar o local salvo no estado do dispositivo. Isso requer componentes que leem esse valor do Registro para poder lidar com esse valor do Registro sendo o caminho completo para um arquivo em vez de um arquivo relativo ao %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"