Exécution à partir du magasin de pilotes
Un fichier INF qui utilise « run from Driver Store » signifie que le fichier INF utilise DIRID 13 pour spécifier l’emplacement des fichiers de package de pilotes à installer.
Pour un fichier « run from Driver Store » chargé par un fichier INF, le sous-répertoire répertorié dans l’entrée SourceDisksFiles pour le fichier dans le fichier INF doit correspondre au sous-répertoire répertorié dans l’entrée DestinationDirs pour le fichier dans le fichier INF.
De plus, une directive CopyFiles ne peut pas être utilisée pour renommer un fichier qui est exécuté à partir du magasin de pilotes. Ces restrictions sont nécessaires pour que l’installation d’un fichier INF sur un périphérique ne résulte pas en la création de nouveaux fichiers dans le répertoire du magasin de pilotes.
Étant donné que les entrées SourceDisksFiles ne peuvent pas avoir plusieurs entrées avec le même nom de fichier et que CopyFiles ne peut pas être utilisé pour renommer un fichier, chaque fichier « exécuté à partir du magasin de pilotes » (run from Driver Store) auquel un fichier INF fait référence doit avoir un nom de fichier unique.
Les packages de pilotes bénéficient d’une prise en charge générale de « run from Driver Store » à partir de Windows 10 1709. Cependant, certaines piles de périphériques peuvent imposer des restrictions supplémentaires sur les fichiers que vous devez fournir qui se branchent dans cette pile. Voici quelques exemples de ces piles de périphériques qui ne prenaient pas en charge « run from Driver Store » avant Windows 10 1803 :
Binaires de pilote UMDF : veuillez consulter la rubrique Restriction de l’emplacement de chargement des pilotes UMDF pour plus d’informations
Mise à jour du firmware UEFI : veuillez consulter la section Rédaction d’un package de pilotes de mise à jour pour plus d’informations
Si vous fournissez un fichier binaire qui se connecte à une pile d’appareils particulière, veuillez consulter la documentation relative à la pile d’appareils spécifique que vous connectez à case activée s’il prend en charge la fourniture d’un chemin d’accès complet au fichier binaire et s’il existe des restrictions sur ce chemin d’accès complet du fichier. S’il prend en charge la fourniture d’un chemin d’accès complet au binaire sans aucune restriction sur ce chemin, alors il devrait prendre en charge le fichier « run from Driver Store » (exécuté à partir du magasin de pilotes).
Recherche et chargement dynamiques de fichiers à partir du magasin de pilotes
Parfois, il est nécessaire qu’un composant charge un fichier qui fait partie d’un package de pilotes utilisant « run from Driver Store ». Les chemins d’accès à ces fichiers de package de pilotes ne doivent pas être codés en dur, car ils peuvent être différents entre différentes versions du package de pilotes, différentes versions du système d’exploitation, différentes éditions du système d’exploitation, etc. Lorsqu’il est nécessaire de charger des fichiers de package de pilotes, ces fichiers de package de pilotes doivent être découverts et chargés dynamiquement à l’aide de certains paradigmes décrits ci-dessous.
Recherche et chargement de fichiers dans le même package de pilotes
Lorsqu’un fichier dans un package de pilotes doit charger un autre fichier du même package de pilotes, une option potentielle pour découvrir dynamiquement ce fichier est de déterminer le répertoire à partir duquel ce fichier s’exécute et de charger l’autre fichier relativement à ce répertoire.
Un pilote WDM ou KMDF qui s’exécute à partir du magasin de pilotes sur Windows 10 version 1803 et les versions ultérieures et qui doit accéder à d’autres fichiers de son package de pilotes doit appeler IoGetDriverDirectory avec DriverDirectoryImage comme type de répertoire pour obtenir le chemin d’accès du répertoire à partir duquel le pilote a été chargé. Alternativement, pour les pilotes qui doivent prendre en charge les versions du système d’exploitation antérieures à Windows 10 version 1803, utilisez IoQueryFullDriverPath pour trouver le chemin d’accès du pilote, obtenir le chemin d’accès du répertoire à partir duquel il a été chargé et rechercher les fichiers relativement à ce chemin. Si le pilote en mode noyau est un pilote KMDF, il peut utiliser WdfDriverWdmGetDriverObject pour récupérer l’objet pilote WDM à passer à IoQueryFullDriverPath.
Les binaires en mode utilisateur peuvent utiliser GetModuleHandleExW et GetModuleFileNameW pour déterminer d’où le binaire a été chargé. Par exemple, un binaire de pilote UMDF peut faire quelque chose comme suit :
bRet = GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
(PCWSTR)&DriverEntry,
&handleModule);
if (bRet) {
charsWritten = GetModuleFileNameW(handleModule,
path,
pathLength);
…
Recherche et chargement de fichiers dans n’importe quel package de pilotes
Dans certains scénarios, un package de pilotes peut contenir un fichier destiné à être chargé par un binaire dans un autre package de pilotes ou par un composant en mode utilisateur. Cette méthode peut également être utilisée pour les fichiers du même package de pilotes si cela est préféré à la méthode décrite ci-dessus pour charger des fichiers du même package de pilotes.
Voici quelques exemples de scénarios qui peuvent impliquer le chargement de fichiers à partir d’un package de pilotes :
Une DLL en mode utilisateur dans un package de pilotes fournit une interface pour communiquer avec un pilote dans le package de pilotes.
Un package de pilotes d’extension contient un fichier de configuration qui est chargé par le pilote dans le package de pilotes de base.
Dans ces situations, le package de pilotes doit définir un état sur un périphérique ou une interface de périphérique indiquant le chemin d’accès du fichier qui est censé être chargé.
Un package de pilotes utiliserait généralement un HKR AddReg pour définir cet état. Pour cet exemple, il faut supposer que pour ExampleFile.dll
, le package de pilotes a une entrée SourceDisksFiles sans sous-répertoire. Cela a pour conséquence que le fichier se trouve à la racine du répertoire du package de pilotes. Il faut également supposer que les DestinationDirs pour une directive CopyFiles spécifie dirid 13.
Voici un exemple d’INF pour définir ceci en tant qu’état de périphérique :
[ExampleDDInstall.HW]
AddReg = Example_DDInstall.AddReg
[Example_DDInstall.AddReg]
HKR,,ExampleValue,,%13%\ExampleFile.dll
Un exemple d’INF pour définir ceci en tant qu’état d’interface de périphérique serait :
[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
Les exemples précédents utilisent une valeur de drapeaux vide, ce qui donne une valeur de Registre REG_SZ. Cela a pour conséquence que le %13% est transformé en un chemin d’accès de fichier en mode utilisateur entièrement qualifié. Dans de nombreux cas, il est préférable que le chemin soit relatif à une variable d’environnement. Si une valeur de drapeaux de 0x20000 est utilisée, la valeur du Registre est de type REG_EXPAND_SZ et le %13% se convertit en un chemin avec des variables d’environnement appropriées pour abstraire l’emplacement du chemin. Lors de la récupération de cette valeur de registre, appelez ExpandEnvironmentStrings pour résoudre les variables d’environnement dans le chemin.
Si la valeur doit être lue par un composant en mode noyau, la valeur doit être une valeur REG_SZ. Lorsque le composant en mode noyau lit cette valeur, il doit préfixer \??\
avant de la passer à des API telles que ZwOpenFile.
Pour accéder à ce paramètre lorsqu’il fait partie de l’état du périphérique, l’application doit d’abord trouver l’identité du périphérique. Le code en mode utilisateur peut utiliser CM_Get_Device_ID_List_Size et CM_Get_Device_ID_List pour obtenir une liste de périphériques, filtrée si nécessaire. Cette liste de périphériques peut contenir plusieurs périphériques, donc recherchez le périphérique approprié avant de lire l’état du périphérique. Par exemple, appelez CM_Get_DevNode_Property pour récupérer des propriétés sur le périphérique lors de la recherche d’un périphérique correspondant à des critères spécifiques.
Une fois que le périphérique correct est trouvé, appelez CM_Open_DevNode_Key pour obtenir un handle vers l’emplacement du registre où l’état du périphérique a été stocké.
Le code en mode noyau doit récupérer un PDO (objet de périphérique physique) vers le périphérique avec l’état et appeler IoOpenDeviceRegistryKey. Le code en mode noyau peut entre autres récupérer le PDO du périphérique en découvrant une interface activée exposée par le périphérique et en utilisant IoGetDeviceObjectPointer pour récupérer l’objet périphérique.
Pour accéder à ce paramètre lorsqu’il s’agit de l’état de l’interface de périphérique, le code en mode utilisateur peut appeler CM_Get_Device_Interface_List_Size et CM_Get_Device_Interface_List.
De plus, CM_Register_Notification peut être utilisé pour être notifié des arrivées et des retraits des interfaces de périphériques afin que le code soit informé lorsque l’interface est activée et puisse ensuite récupérer l’état. Il peut y avoir plusieurs interfaces de périphérique dans la classe d’interface de périphérique utilisée dans les API ci-dessus. Examinez ces interfaces pour déterminer laquelle est l’interface correcte pour lire le paramètre.
Une fois que l’interface de périphérique correcte est trouvée, appelez CM_Open_Device_Interface_Key.
Le code en mode noyau peut récupérer un nom de lien symbolique pour l’interface de périphérique à partir de laquelle obtenir l’état. Pour ce faire, appelez IoRegisterPlugPlayNotification pour vous inscrire aux notifications d’interface de périphérique sur la classe d’interface de périphérique appropriée. Sinon, vous pouvez aussi appeler IoGetDeviceInterfaces pour obtenir une liste des interfaces de périphériques actuelles sur le système. Il peut y avoir plusieurs interfaces de périphérique dans la classe d’interface de périphérique utilisée dans les API ci-dessus. Examinez ces interfaces pour déterminer laquelle est l’interface correcte qui devrait avoir le paramètre à lire.
Une fois que le nom de lien symbolique approprié est trouvé, appelez IoOpenDeviceInterfaceRegistryKey pour récupérer une poignée vers l’emplacement du registre où l’état de l’interface de périphérique était stocké.
Remarque
Utilisez l’indicateur CM_GETIDLIST_FILTER_PRESENT avec CM_Get_Device_ID_List_Size et CM_Get_Device_ID_List ou l’indicateur CM_GET_DEVICE_INTERFACE_LIST_PRESENT avec CM_Get_Device_Interface_List_Size et CM_Get_Device_Interface_List. Cela garantit que le matériel lié à l’état contenant le chemin d’accès au fichier est présent et prêt pour la communication.
Suppression du package de pilotes
Par défaut, un package de pilotes ne peut pas être supprimé du système s’il est toujours installé sur des périphériques. Cependant, certaines options permettent de tenter de le supprimer de force. Cela tente de supprimer le package de pilotes même s’il est toujours installé sur certains périphériques du système. Les suppressions forcées ne sont pas autorisées pour les packages de pilotes qui contiennent des fichiers exécutés à partir du magasin de pilotes. Lorsqu’un package de pilotes est supprimé du système, son contenu de magasin de pilotes est également supprimé. S’il reste des périphériques installés avec ce package de pilotes, tous les fichiers exécutés à partir du magasin de pilotes dans ce package de pilotes seront maintenant supprimés et ces fichiers manquants peuvent entraîner un dysfonctionnement de ce périphérique. Pour éviter de mettre le périphérique dans un état de dysfonctionnement, les packages de pilotes contenant des fichiers exécutés à partir du magasin de pilotes ne peuvent pas être supprimés de force. Ils ne peuvent être supprimés que lorsqu’ils ne sont plus installés sur aucun périphérique. Pour aider à supprimer de tels packages de pilotes, DiUninstallDriver ou pnputil /delete-driver <oem#.inf> /uninstall peuvent être utilisés. Ces méthodes de suppression mettront d’abord à jour tous les périphériques utilisant le package de pilotes à supprimer pour ne plus être installés avec ce package de pilotes avant de tenter de supprimer le package de pilotes.
Développement de package de pilotes
Test de binaires privés
Lors du développement d’un package de pilotes, s’il est nécessaire de remplacer un fichier exécutable particulier du package de pilotes par une version privée au lieu de reconstruire complètement et de remplacer le package de pilotes sur le système, il est recommandé d’utiliser un débogueur de noyau avec la commande .kdfiles. Étant donné que le chemin complet vers le fichier dans le magasin de pilotes ne doit pas être codé en dur, il est recommandé que, dans le mapping de .kdfiles, le nom de fichier OldDriver soit juste le nom direct du fichier sans information du chemin précédent. Pour faciliter cela (et d’autres scénarios), les noms de fichiers dans les packages de pilotes doivent être aussi uniques que possible afin de ne pas correspondre au nom d’un fichier d’un package de pilotes non lié sur le système.
Portage d’une INF pour utiliser l’exécution à partir du magasin de pilotes
Si vous avez un package de pilotes existant avec une INF qui n’utilise pas l’exécution à partir du magasin de pilotes et que vous le portez pour utiliser l’exécution à partir du magasin de pilotes, les exemples suivants montrent certaines utilisations courantes de fichiers dans les INF et les motifs de mise à jour de ces fichiers pour être exécutés à partir de DriverStore.
Référence rapide pour les mises à jour des répertoires de destination
Le tableau suivant est une référence pour trouver rapidement les instructions appropriées en fonction du répertoire de destination actuel DIRID spécifié par un package de pilotes INF pour un fichier.
DIRID | Sous-répertoire | Détails |
---|---|---|
13 | Le fichier utilise déjà « exécuter à partir du magasin de pilotes ». Aucun travail supplémentaire n’est nécessaire. | |
1 | DIRID 1 ne doit pas être utilisé. Il n’y a aucune garantie que le répertoire source sera disponible lorsque qu’une référence au fichier doit être résolue. Au lieu de cela, si les composants du package de pilotes dépendent de fichiers spécifiques, incluez ces fichiers dans le package de pilotes et exécutez-les à partir du magasin de pilotes. | |
10 | Microprogramme | Pour plus d’informations concernant l’utilisation de DIRID 13 avec un package de pilotes de mise à jour du firmware pour le faire utiliser « run from Driver Store », veuillez consulter la Rédaction d’un package de pilotes de mise à jour. |
10 | Voir Autres fichiers. | |
11 | Voir Autres fichiers. | |
12 | UMDF | Voir le fichier binaire du pilote UMDF. |
12 | La plupart des fichiers avec une destination de DIRID 12 représentent des binaires de service de pilote. Voir Binaire de service. | |
16422, 16426, 16427, 16428 | La plupart des fichiers avec une destination de ces DIRIDs représentent l’installation d’une application. Au lieu de cela, fournissez une application Universal Windows Platform (UWP) et installez-la à l’aide d’une directive AddSoftware d’une section DDInstall.Software du package de pilotes INF. Pour plus de détails, veuillez consulter la section Lier un pilote avec une application Universal Windows Platform (UWP). |
Binaire de service
Si votre INF ajoute un service et que le binaire n’est pas exécuté à partir du magasin de pilotes, alors votre INF peut ressembler à ceci :
[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
Pour déplacer ce fichier pour qu’il soit exécuté à partir du magasin de pilotes, vous devriez mettre à jour l’entrée DestinationDirs pour indiquer où le fichier sera copié et mettre à jour la directive ServiceBinary en référençant l’emplacement de ce fichier.
[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
Binaire de pilote UMDF
Si votre INF ajoute un pilote UMDF et que le binaire n’est pas exécuté à partir du magasin de pilotes, alors votre INF peut ressembler à ceci :
[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
...
Pour déplacer ce fichier pour qu’il soit exécuté à partir du magasin de pilotes, vous devriez mettre à jour l’entrée DestinationDirs pour indiquer où le fichier sera copié et mettre à jour la directive ServiceBinary en référençant l’emplacement de ce fichier.
[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
...
Autres fichiers
Si votre INF ajoute un fichier qui peut être chargé par d’autres composants et qui n’est pas exécuté à partir du magasin de pilotes, alors votre INF peut ressembler à ce qui suit. Dans cet exemple, seul le nom du fichier est écrit dans l’état du registre du périphérique. Les composants qui lisent cette valeur de registre pour déterminer quel fichier charger dépendront du fait que le fichier soit dans %windir%\system32
ou dépendra de l’ordre de recherche de LoadLibrary pouvant trouver le fichier.
[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"
Pour déplacer ce fichier pour qu’il soit exécuté à partir du magasin de pilotes, vous devriez mettre à jour l’entrée DestinationDirs pour indiquer où le fichier sera copié et mettre à jour l’emplacement enregistré dans l’état du périphérique. Cela nécessite que les composants qui lisent cette valeur de registre puissent gérer le fait que cette valeur de registre soit le chemin complet vers un fichier au lieu d’un fichier relatif à %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"