Ejecutar desde el almacén de controladores
Un INF que usa "ejecutar desde el almacén de controladores" significa que el INF usa DIRID 13 para especificar la ubicación de los archivos del paquete de controladores en la instalación.
Para un archivo de tipo "ejecutar desde el almacén de controladores" cargado por un INF, el subdir enumerado en la entrada SourceDisksFiles para el archivo en el INF debe coincidir con el subdir enumerado en la entrada DestinationDirs del archivo en INF.
Además, no se puede usar una directiva CopyFiles para cambiar el nombre de un archivo que se ejecuta desde el almacén de controladores. Estas restricciones son necesarias para que la instalación de un INF en un dispositivo no produzca la creación de nuevos archivos en el directorio del almacén de controladores.
Dado que las entradas SourceDisksFiles no pueden tener varias entradas con el mismo nombre de archivo y CopyFiles no se puede usar para cambiar el nombre de un archivo, todos los archivos de tipo "ejecutar desde el almacén de controladores" al que hace referencia INF deben tener un nombre de archivo único.
Los paquetes de controladores tienen compatibilidad general con "ejecutar desde el almacén de controladores" a partir de Windows 10 1709. Sin embargo, algunas pilas de dispositivos pueden imponer restricciones adicionales a los archivos que debe proporcionar y que se conectan a esa pila. Algunos ejemplos son estas pilas de dispositivos que no admiten la opción de "ejecutar desde el almacén de controladores" hasta Windows 10 1803:
Archivos binarios del controlador UMDF: consulte Restricción de la ubicación de carga de controladores UMDF para obtener más información.
Actualización de firmware de UEFI: consulte Creación de un paquete de controladores de actualización para obtener más información.
Si proporciona un binario que se conecta a una pila de dispositivos determinada, consulte la documentación de la pila de dispositivos específica en la que está conectando para comprobar si admite proporcionar una ruta de acceso completa al archivo binario y si hay alguna restricción en esa ruta de acceso de archivo completa. Si admite proporcionar una ruta de acceso completa al archivo binario sin restricciones en esa ruta de acceso, debe admitir el archivo de tipo "ejecutar desde el almacén de controladores".
Búsqueda y carga dinámica de archivos desde el almacén de controladores
A veces, es necesario que un componente cargue un archivo que forme parte de un paquete de controladores que use "ejecutar desde el almacén de controladores". Las rutas de acceso a estos archivos de paquetes de controladores no deben codificarse de forma fija, ya que pueden ser diferentes entre diferentes versiones del paquete de controladores, diferentes versiones del sistema operativo, diferentes ediciones del sistema operativo, etc. Cuando surja la necesidad de cargar archivos de paquetes de controladores, estos archivos de paquetes de controladores deben detectarse y cargarse dinámicamente utilizando algunos de los paradigmas descritos a continuación.
Búsqueda y carga de archivos en el mismo paquete de controladores
Cuando un archivo de un paquete de controladores necesita cargar otro archivo desde el mismo paquete de controladores, una posible opción para detectar dinámicamente ese archivo es determinar el directorio desde el que se ejecuta y cargar el otro archivo en relación con ese directorio.
Un controlador WDM o KMDF que se ejecuta desde el almacén de controladores en Windows 10 versión 1803 y posteriores que necesita tener acceso a otros archivos desde su paquete de controladores debe llamar a IoGetDriverDirectory con DriverDirectoryImage como tipo de directorio para obtener la ruta de acceso del directorio desde el que se cargó el controlador. Como alternativa, para los controladores que necesitan admitir versiones del sistema operativo anteriores a la versión 1803 de Windows 10, use IoQueryFullDriverPath para buscar la ruta de acceso del controlador, obtener la ruta de acceso del directorio desde el que se cargó y buscar archivos relativos a esa ruta de acceso. Si el controlador del modo kernel es un controlador KMDF, puede usar WdfDriverWdmGetDriverObject para recuperar el objeto de controlador WDM para transferirlo a IoQueryFullDriverPath.
Los archivos binarios del modo de usuario pueden usar GetModuleHandleExW y GetModuleFileNameW para determinar desde dónde se cargó el archivo binario. Por ejemplo, un archivo binario del controlador UMDF puede hacer algo parecido a lo siguiente:
bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(PCWSTR)&DriverEntry,
&handleModule);
if (bRet) {
charsWritten = GetModuleFileNameW(handleModule,
path,
pathLength);
…
Buscar y cargar archivos en cualquier paquete de controladores
En algunos escenarios, un paquete de controladores puede contener un archivo que está pensado para que lo cargue un archivo binario en otro paquete de controladores o un componente de modo de usuario. Este método también se puede usar para archivos del mismo paquete de controladores si se prefiere sobre el método descrito anteriormente, para cargar archivos desde el mismo paquete de controladores.
Estos son un par de ejemplos de escenarios que pueden implicar la carga de archivos desde un paquete de controladores:
Un archivo DLL en modo de usuario en un paquete de controladores proporciona una interfaz para comunicarse con un controlador en el paquete de controladores.
Un paquete de controladores de extensión contiene un archivo de configuración que el controlador carga en el paquete de controladores base.
En estas situaciones, el paquete de controladores debe establecer algún estado en un dispositivo o interfaz de dispositivo que indique la ruta de acceso del archivo que se espera que se cargue.
Normalmente, un paquete de controladores usaría un AddReg de HKR para establecer este estado. En este ejemplo, se debe suponer que para ExampleFile.dll
, el paquete de controladores tiene una entrada SourceDisksFiles sin subdir. Esto da como resultado que el archivo se encuentra en la raíz del directorio del paquete de controladores. También se debe suponer que DestinationDirs para una directiva CopyFiles especifica dirid 13.
Este es un ejemplo de INF para establecerlo como estado del dispositivo:
[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg
[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll
Un ejemplo de INF para establecer esto como estado de interfaz de dispositivo sería:
[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
En los ejemplos anteriores se usa un valor de marcas vacías, lo que da como resultado un valor del Registro de REG_SZ. Esto da como resultado que %13% se convierta en una ruta de acceso de archivo en modo de usuario completa. En muchos casos, es preferible que la ruta de acceso sea relativa a una variable de entorno. Si se usa un valor de marcas de 0x20000, el valor del Registro es de tipo REG_EXPAND_SZ y el %13% se convierte en una ruta de acceso con variables de entorno adecuadas para abstraer la ubicación de la ruta de acceso. Al recuperar este valor del Registro, llama a ExpandEnvironmentStrings para resolver las variables de entorno en la ruta de acceso.
Si un componente de modo kernel debe leer el valor, el valor debe ser un valor REG_SZ. Cuando el componente del modo kernel lee ese valor, debe anteponer \??\
antes de transferirlo a las API, como ZwOpenFile.
Para acceder a esta configuración cuando forma parte del estado del dispositivo, primero la aplicación debe encontrar la identidad del dispositivo. El código en modo de usuario puede usar CM_Get_Device_ID_List_Size y CM_Get_Device_ID_List para obtener una lista de dispositivos, filtrados según sea necesario. Esa lista de dispositivos puede contener varios dispositivos, así que busque el dispositivo adecuado antes de leer el estado del dispositivo. Por ejemplo, llame a CM_Get_DevNode_Property para recuperar propiedades en el dispositivo cuando busque un dispositivo que coincida con criterios específicos.
Una vez encontrado el dispositivo correcto, llame a CM_Open_DevNode_Key para obtener un identificador a la ubicación del Registro donde se almacenó el estado del dispositivo.
El código del modo kernel debe recuperar un PDO (objeto de dispositivo físico) en el dispositivo con el estado y llamar a IoOpenDeviceRegistryKey. Una posible manera de que el código del modo kernel recupere el PDO del dispositivo sería detectar una interfaz habilitada expuesta por el dispositivo y usar IoGetDeviceObjectPointer para recuperar el objeto de dispositivo.
Para acceder a esta configuración cuando se trata del estado de la interfaz de dispositivo, el código en modo de usuario puede llamar a CM_Get_Device_Interface_List_Size y CM_Get_Device_Interface_List.
Además , se puede usar CM_Register_Notification para recibir notificaciones de llegadas y eliminaciones de interfaces de dispositivo para que el código reciba una notificación cuando la interfaz esté habilitada y, a continuación, pueda recuperar el estado. Puede haber varias interfaces de dispositivo en la clase de interfaz de dispositivo usada en las API anteriores. Examine esas interfaces para determinar cuál es la interfaz correcta para la configuración que se va a leer.
Una vez que se encuentre la interfaz de dispositivo correcta, llame a CM_Open_Device_Interface_Key.
El código del modo kernel puede recuperar un nombre de vínculo simbólico para la interfaz de dispositivo desde la que obtener el estado. Para ello, llame a IoRegisterPlugPlayNotification para registrarse para recibir notificaciones de la interfaz de dispositivo en la clase de interfaz de dispositivo adecuada. Como alternativa, llame a IoGetDeviceInterfaces para obtener una lista de las interfaces de dispositivo actuales en el sistema. Puede haber varias interfaces de dispositivo en la clase de interfaz de dispositivo usada en las API anteriores. Examine esas interfaces para determinar cuál es la interfaz correcta que debe tener la configuración que se va a leer.
Una vez encontrado el nombre del vínculo simbólico adecuado, llame a IoOpenDeviceInterfaceRegistryKey para recuperar un identificador de la ubicación del Registro donde se almacenó el estado de la interfaz del dispositivo.
Nota:
Use la marca CM_GETIDLIST_FILTER_PRESENT con CM_Get_Device_ID_List_Size y CM_Get_Device_ID_List o la marca CM_GET_DEVICE_INTERFACE_LIST_PRESENT con CM_Get_Device_Interface_List_Size y CM_Get_Device_Interface_List. Esto garantiza que el hardware relacionado con el estado que contiene la ruta de acceso del archivo está presente y listo para la comunicación.
Eliminación del paquete de controladores
De forma predeterminada, un paquete de controladores no se puede eliminar del sistema si todavía está instalado en cualquier dispositivo. Sin embargo, algunas opciones para eliminar un paquete de controladores del sistema permiten que se intente eliminar por la "fuerza". Esto intenta eliminar el paquete de controladores incluso si ese paquete de controladores todavía está instalado en algunos dispositivos del sistema. No se permiten eliminaciones forzadas para los paquetes de controladores que tienen archivos de tipo "ejecutar desde el almacén de controladores". Cuando se elimina un paquete de controladores del sistema, se elimina su contenido del almacén de controladores. Si hay dispositivos que todavía están instalados con ese paquete de controladores, los archivos de tipo "ejecutar desde el almacén de controladores" de ese paquete de controladores ahora se perderán y esos archivos que faltan pueden provocar que el dispositivo funcione mal. Para evitar que el dispositivo se coloque en un estado incorrecto, los paquetes de controladores que contienen archivos de tipo "ejecutar desde el almacén de controladores" no se pueden eliminar. Solo se pueden eliminar una vez que ya no estén instalados en ningún dispositivo. Para ayudar en las eliminaciones de estos paquetes de controladores, se puede usar DiUninstallDriver o pnputil /delete-driver <oem#.inf> /uninstall. Estos métodos de eliminación actualizarán primero los dispositivos que usen el paquete de controladores que se va a eliminar para que ya no se instalen con ese paquete de controladores antes de intentar eliminar el paquete de controladores.
Desarrollo de paquetes de controladores
Prueba de archivos binarios privados
Al desarrollar un paquete de controladores, si es necesario reemplazar un archivo ejecutable determinado del paquete de controladores por una versión privada en lugar de volver a generar completamente y reemplazar el paquete de controladores en el sistema, se recomienda usar un depurador de kernel junto con el comando .kdfiles. Dado que la ruta de acceso completa al archivo del almacén de controladores no debe codificarse de forma fija, se recomienda que en la asignación .kdfiles, el nombre de archivo OldDriver sea solo el nombre directo del archivo sin información de ruta de acceso anterior. Para facilitar este escenario (y otros), los nombres de archivos de los paquetes de controladores deben ser lo más únicos posible para que no coincidan con el nombre de un archivo de un paquete de controladores no relacionado en el sistema.
Migración de un INF para usar la ejecución desde el almacén de controladores
Si tiene un paquete de controladores existente con un INF que no usa la ejecución desde el almacén de controladores y lo está portando para usarlo desde el almacén de controladores, en los ejemplos siguientes se muestran algunos usos comunes de archivos en INF y patrones sobre cómo actualizar esos archivos para que se ejecuten desde el almacén de controladores.
Referencia rápida para las actualizaciones del directorio de destino
En la tabla siguiente se proporciona una referencia rápida para buscar las instrucciones adecuadas en función del DIRID del directorio de destino actual que especifica un archivo INF del paquete de controladores para un archivo.
DIRID | Subdirectorio | Detalles |
---|---|---|
13 | El archivo ya usa "ejecutar desde el almacén de controladores". No es necesario realizar ningún trabajo adicional. | |
1 | No se debe usar DIRID 1. No hay ninguna garantía de que el directorio de origen estará disponible cuando se necesite resolver una referencia al archivo. En su lugar, si los componentes del paquete de controladores dependen de archivos específicos, incluya esos archivos en el paquete de controladores y ejecútelos desde el almacén de controladores. | |
10 | Firmware | Para obtener información sobre cómo usar DIRID 13 con un paquete de controladores de actualización de firmware para que use "ejecutar desde el almacén de controladores", consulte Creación de un paquete de controladores de actualización. |
10 | Consulte Otros archivos. | |
11 | Consulte Otros archivos. | |
12 | UMDF | Consulte Archivo binario del controlador UMDF. |
12 | La mayoría de los archivos con un destino de DIRID 12 representan archivos binarios del servicio de controladores. Consulte Archivo binario de servicio. | |
16422, 16426, 16427, 16428 | La mayoría de los archivos con un destino de estos DIRID representan la instalación de una aplicación. En su lugar, proporcione una aplicación de Plataforma universal de Windows (UWP) e instálela mediante una directiva AddSoftware de una sección DDInstall.Software del INF del paquete de controladores. Para obtener más información, consulte Emparejamiento de un controlador con una aplicación de Plataforma universal de Windows (UWP). |
Archivo binario de servicio
Si el INF agrega un servicio y el archivo binario no se ejecuta desde el almacén de controladores, es posible que el INF tenga el siguiente aspecto:
[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 este archivo para que se ejecute desde el almacén de controladores, tendría que actualizar la entrada DestinationDirs donde se copiará el archivo y actualizar la directiva ServiceBinary que hace referencia a la ubicación de este archivo.
[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
Archivo binario del controlador UMDF
Si el INF agrega un controlador UMDF y el archivo binario no se ejecuta desde el almacén de controladores, es posible que el INF tenga el siguiente aspecto:
[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 este archivo para que se ejecute desde el almacén de controladores, tendría que actualizar la entrada DestinationDirs donde se copiará el archivo y actualizar la directiva ServiceBinary que hace referencia a la ubicación de este archivo.
[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
...
Otros archivos
Si el INF agrega un archivo que otros componentes pueden cargar y no se ejecuta desde el almacén de controladores, es posible que el INF tenga el siguiente aspecto. En este ejemplo, solo se escribe el nombre del archivo en el estado del registro del dispositivo. Los componentes que leen este valor del registro para determinar qué archivo cargar dependerían de que el archivo estuviera en %windir%\system32
o dependerían de que el orden de búsqueda de LoadLibrary pudiera encontrar el archivo.
[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 este archivo para que se ejecute desde el almacén de controladores, tendría que actualizar la entrada DestinationDirs donde se copiará el archivo y actualizar la ubicación guardada en el estado del dispositivo. Esto requiere que los componentes que leen ese valor del registro sean capaces de manejar ese valor del registro siendo la ruta de acceso completa a un archivo en lugar de un archivo 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"