Partager via


Écrire un pilote Hello World Windows (KMDF)

Cet article explique comment écrire un petit pilote Windows universel à l’aide de Kernel-Mode Driver Framework (KMDF), puis comment déployer et installer votre pilote sur un ordinateur distinct.

Avant de continuer, effectuez les étapes d’installation répertoriées dans Télécharger le Kit de pilotes Windows (WDK).

Les outils de débogage pour Windows sont inclus lorsque vous installez le WDK.

Créer et générer un pilote

  1. Ouvrez Microsoft Visual Studio. Dans le menu Fichier , choisissez Nouveau > projet.

  2. Dans la boîte de dialogue Créer un projet , sélectionnez C++ dans la liste déroulante de gauche, choisissez Windows dans la liste déroulante du milieu, puis choisissez Pilote dans la liste déroulante de droite.

  3. Sélectionnez Pilote en mode noyau, Vide (KMDF) dans la liste des types de projets. Sélectionnez Suivant.

    Capture d’écran de la boîte de dialogue Nouveau projet Visual Studio avec l’option de pilote en mode noyau sélectionnée.

  4. Dans la boîte de dialogue Configurer votre nouveau projet , entrez « KmdfHelloWorld » dans le champ Nom du projet .

    Notes

    Lorsque vous créez un pilote KMDF ou UMDF, vous devez sélectionner un nom de pilote contenant 32 caractères ou moins. Cette limite de longueur est définie dans wdfglobals.h.

  5. Dans le champ Emplacement , entrez le répertoire dans lequel vous souhaitez créer le projet.

  6. Cochez Placer la solution et le projet dans le même répertoire , puis sélectionnez Créer.

    Capture d’écran de la boîte de dialogue Configurer votre nouveau projet dans Visual Studio avec le bouton Créer mis en surbrillance.

    Visual Studio crée un projet et une solution. Ceux-ci sont visibles dans la fenêtre Explorateur de solutions. (Si la fenêtre Explorateur de solutions n’est pas visible, choisissez Explorateur de solutions dans le menu Affichage.) La solution a un projet de pilote nommé KmdfHelloWorld.

    Capture d’écran de la fenêtre explorateur de solutions Visual Studio affichant la solution et le projet de pilote vide nommé KmdfHelloWorld.

  7. Dans la fenêtre Explorateur de solutions, sélectionnez et maintenez la solution KmdfHelloWorld enfoncée (ou sélectionnez avec le bouton droit) et choisissez Configuration Manager. Choisissez une configuration et une plateforme pour le projet de pilote. Par exemple, choisissez Déboguer et x64.

  8. Dans la fenêtre Explorateur de solutions, sélectionnez de nouveau le projet KmdfHelloWorld de façon enfoncée (ou sélectionnez avec le bouton droit), choisissez Ajouter, puis sélectionnez Nouvel élément.

  9. Dans la boîte de dialogue Ajouter un nouvel élément , sélectionnez Fichier C++. Pour Nom, entrez « Driver.c ».

    Notes

    L’extension de nom de fichier est .c, et non .cpp.

    Sélectionnez Ajouter. Le fichier Driver.c est ajouté sous Fichiers sources, comme illustré ici.

    Capture d’écran de la fenêtre explorateur de solutions Visual Studio affichant le fichier driver.c ajouté au projet de pilote.

Écrire votre premier code de pilote

Maintenant que vous avez créé votre projet de Hello World vide et ajouté le fichier source Driver.c, vous allez écrire le code le plus simple nécessaire à l’exécution du pilote en implémentant deux fonctions de rappel d’événements de base.

  1. Dans Driver.c, commencez par inclure les en-têtes suivants :

    #include <ntddk.h>
    #include <wdf.h>
    

    Conseil

    Si vous ne pouvez pas ajouter Ntddk.h, ouvrez Configuration -> C/C++ -> Général -> Répertoires Include supplémentaires et ajoutez C:\Program Files (x86)\Windows Kits\10\Include\<build#>\km, en <build#> remplaçant par le répertoire approprié dans votre installation WDK.

    Ntddk.h contient des définitions de noyau Windows principales pour tous les pilotes, tandis que Wdf.h contient des définitions pour les pilotes basés sur Windows Driver Framework (WDF).

  2. Ensuite, fournissez des déclarations pour les deux rappels que vous utiliserez :

    DRIVER_INITIALIZE DriverEntry;
    EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
    
  3. Utilisez le code suivant pour écrire votre DriverEntry :

    NTSTATUS 
    DriverEntry(
        _In_ PDRIVER_OBJECT     DriverObject, 
        _In_ PUNICODE_STRING    RegistryPath
    )
    {
        // NTSTATUS variable to record success or failure
        NTSTATUS status = STATUS_SUCCESS;
    
        // Allocate the driver configuration object
        WDF_DRIVER_CONFIG config;
    
        // Print "Hello World" for DriverEntry
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" ));
    
        // Initialize the driver configuration object to register the
        // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
        WDF_DRIVER_CONFIG_INIT(&config, 
                               KmdfHelloWorldEvtDeviceAdd
                               );
    
        // Finally, create the driver object
        status = WdfDriverCreate(DriverObject, 
                                 RegistryPath, 
                                 WDF_NO_OBJECT_ATTRIBUTES, 
                                 &config, 
                                 WDF_NO_HANDLE
                                 );
        return status;
    }
    

    DriverEntry est le point d’entrée pour tous les pilotes, comme c’est le cas Main() pour de nombreuses applications en mode utilisateur. Le travail de DriverEntry consiste à initialiser des structures et des ressources à l’échelle du pilote. Dans cet exemple, vous avez imprimé « Hello World » pour DriverEntry, configuré l’objet driver pour inscrire le point d’entrée de votre rappel EvtDeviceAdd, puis créé l’objet driver et retourné.

    L’objet driver agit en tant qu’objet parent pour tous les autres objets d’infrastructure que vous pouvez créer dans votre pilote, notamment les objets d’appareil, les files d’attente d’E/S, les minuteurs, les verrouillages tournants, etc. Pour plus d’informations sur les objets d’infrastructure, consultez Présentation des objets d’infrastructure.

    Conseil

    Pour DriverEntry, nous vous recommandons vivement de conserver le nom « DriverEntry » pour faciliter l’analyse et le débogage du code.

  4. Ensuite, utilisez le code suivant pour écrire votre KmdfHelloWorldEvtDeviceAdd :

    NTSTATUS 
    KmdfHelloWorldEvtDeviceAdd(
        _In_    WDFDRIVER       Driver, 
        _Inout_ PWDFDEVICE_INIT DeviceInit
    )
    {
        // We're not using the driver object,
        // so we need to mark it as unreferenced
        UNREFERENCED_PARAMETER(Driver);
    
        NTSTATUS status;
    
        // Allocate the device object
        WDFDEVICE hDevice;    
    
        // Print "Hello World"
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" ));
    
        // Create the device object
        status = WdfDeviceCreate(&DeviceInit, 
                                 WDF_NO_OBJECT_ATTRIBUTES,
                                 &hDevice
                                 );
        return status;
    }
    

    EvtDeviceAdd est appelé par le système lorsqu’il détecte que votre appareil est arrivé. Son travail consiste à initialiser des structures et des ressources pour cet appareil. Dans cet exemple, vous avez simplement imprimé un message « Hello World » pour EvtDeviceAdd, créé l’objet d’appareil et retourné. Dans d’autres pilotes que vous écrivez, vous pouvez créer des files d’attente d’E/S pour votre matériel, configurer un espace de stockage de contexte de périphérique pour les informations spécifiques à l’appareil ou effectuer d’autres tâches nécessaires à la préparation de votre appareil.

    Conseil

    Pour le rappel d’ajout d’appareil, notez comment vous l’avez nommé avec le nom de votre pilote comme préfixe (KmdfHelloWorldEvtDeviceAdd). En règle générale, nous vous recommandons de nommer les fonctions de votre pilote de cette façon pour les différencier des fonctions des autres pilotes. DriverEntry est le seul que vous devez nommer exactement cela.

  5. Votre fichier Driver.c complet ressemble maintenant à ceci :

    #include <ntddk.h>
    #include <wdf.h>
    DRIVER_INITIALIZE DriverEntry;
    EVT_WDF_DRIVER_DEVICE_ADD KmdfHelloWorldEvtDeviceAdd;
    
    NTSTATUS 
    DriverEntry(
        _In_ PDRIVER_OBJECT     DriverObject, 
        _In_ PUNICODE_STRING    RegistryPath
    )
    {
        // NTSTATUS variable to record success or failure
        NTSTATUS status = STATUS_SUCCESS;
    
        // Allocate the driver configuration object
        WDF_DRIVER_CONFIG config;
    
        // Print "Hello World" for DriverEntry
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: DriverEntry\n" ));
    
        // Initialize the driver configuration object to register the
        // entry point for the EvtDeviceAdd callback, KmdfHelloWorldEvtDeviceAdd
        WDF_DRIVER_CONFIG_INIT(&config, 
                               KmdfHelloWorldEvtDeviceAdd
                               );
    
        // Finally, create the driver object
        status = WdfDriverCreate(DriverObject, 
                                 RegistryPath, 
                                 WDF_NO_OBJECT_ATTRIBUTES, 
                                 &config, 
                                 WDF_NO_HANDLE
                                 );
        return status;
    }
    
    NTSTATUS 
    KmdfHelloWorldEvtDeviceAdd(
        _In_    WDFDRIVER       Driver, 
        _Inout_ PWDFDEVICE_INIT DeviceInit
    )
    {
        // We're not using the driver object,
        // so we need to mark it as unreferenced
        UNREFERENCED_PARAMETER(Driver);
    
        NTSTATUS status;
    
        // Allocate the device object
        WDFDEVICE hDevice;    
    
        // Print "Hello World"
        KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "KmdfHelloWorld: KmdfHelloWorldEvtDeviceAdd\n" ));
    
        // Create the device object
        status = WdfDeviceCreate(&DeviceInit, 
                                 WDF_NO_OBJECT_ATTRIBUTES,
                                 &hDevice
                                 );
        return status;
    }
    
  6. Enregistrez Driver.c.

Cet exemple illustre un concept fondamental des pilotes : il s’agit d’une « collection de rappels » qui, une fois initialisés, restent assis et attendent que le système les appelle lorsqu’il a besoin de quelque chose. Un appel système peut être un événement d’arrivée d’un nouvel appareil, une demande d’E/S d’une application en mode utilisateur, un événement d’arrêt de l’alimentation du système, une demande d’un autre pilote ou un événement de suppression surprise lorsqu’un utilisateur débranche l’appareil de manière inattendue. Heureusement, pour dire « Hello World », il vous suffisait de vous soucier de la création du pilote et de l’appareil.

Ensuite, vous allez créer votre pilote.

Générer le pilote

  1. Dans la fenêtre Explorateur de solutions, sélectionnez la solution « KmdfHelloWorld » (1 projet) de façon enfoncée (ou sélectionnez avec le bouton droit) et choisissez Configuration Manager. Choisissez une configuration et une plateforme pour le projet de pilote. Pour cet exercice, nous choisissons Déboguer et x64.

  2. Dans la fenêtre Explorateur de solutions, sélectionnez kmdfHelloWorld de façon enfoncée (ou sélectionnez avec le bouton droit) et choisissez Propriétés. Dans Toutes les options de suivi > Wpp, définissez Exécuter le suivi Wpp sur Non. Sélectionnez Apply (Appliquer), puis OK.

  3. Pour générer votre pilote, choisissez Générer la solution dans le menu Générer . Visual Studio affiche la progression de la génération dans la fenêtre Sortie . (Si la fenêtre Sortie n’est pas visible, choisissez Sortie dans le menu Affichage .) Une fois que vous avez vérifié que la solution a été correctement générée, vous pouvez fermer Visual Studio.

  4. Pour afficher le pilote généré, dans Explorateur de fichiers, accédez à votre dossier KmdfHelloWorld, puis à x64\Debug\KmdfHelloWorld. Le dossier comprend :

    • KmdfHelloWorld.sys : fichier de pilote en mode noyau
    • KmdfHelloWorld.inf : un fichier d’informations que Windows utilise lorsque vous installez le pilote
    • KmdfHelloWorld.cat : un fichier catalogue que le programme d’installation utilise pour vérifier la signature de test du pilote

Conseil

Si vous voyez DriverVer set to a date in the future lors de la génération de votre pilote, modifiez les paramètres de votre projet de pilote afin que Inf2Cat définit /uselocaltime. Pour ce faire, utilisez Propriétés de configuration-Inf2Cat-Général-Utiliser>>> l’heure locale. À présent, Stampinf et Inf2Cat utilisent l’heure locale.

Déployer le pilote

En règle générale, lorsque vous testez et déboguez un pilote, le débogueur et le pilote s’exécutent sur des ordinateurs distincts. L’ordinateur qui exécute le débogueur est appelé ordinateur hôte, et l’ordinateur qui exécute le pilote est appelé ordinateur cible. L’ordinateur cible est également appelé ordinateur de test.

Jusqu’à présent, vous avez utilisé Visual Studio pour générer un pilote sur l’ordinateur hôte. Vous devez maintenant configurer un ordinateur cible.

  1. Suivez les instructions fournies dans Provisionner un ordinateur pour le déploiement et le test de pilotes (WDK 10).

    Conseil

    Lorsque vous suivez les étapes pour approvisionner automatiquement l’ordinateur cible à l’aide d’un câble réseau, notez le port et la clé. Vous les utiliserez plus tard dans l’étape de débogage. Dans cet exemple, nous allons utiliser 50000 comme port et 1.2.3.4 comme clé.

    Dans les scénarios de débogage de pilote réels, nous vous recommandons d’utiliser une clé générée par KDNET. Pour plus d’informations sur l’utilisation de KDNET pour générer une clé aléatoire, consultez la rubrique Debug Drivers - Step by Step Lab (Sysvad Kernel Mode).

  2. Sur l’ordinateur hôte, ouvrez votre solution dans Visual Studio. Vous pouvez double-cliquer sur le fichier solution, KmdfHelloWorld.sln, dans votre dossier KmdfHelloWorld.

  3. Dans la fenêtre Explorateur de solutions, sélectionnez le projet KmdfHelloWorld de façon enfoncée (ou cliquez avec le bouton droit), puis choisissez Propriétés.

  4. Dans la fenêtre Pages de propriétés KmdfHelloWorld, accédez à Propriétés > de configuration Déploiement du pilote d’installation>, comme illustré ici.

  5. Cochez Supprimer les versions précédentes du pilote avant le déploiement.

  6. Pour Nom de l’appareil cible, sélectionnez le nom de l’ordinateur que vous avez configuré pour le test et le débogage. Dans cet exercice, nous utilisons un ordinateur nommé MyTestComputer.

  7. Sélectionnez Mise à jour du pilote d’ID matériel, puis entrez l’ID matériel de votre pilote. Pour cet exercice, l’ID matériel est Root\KmdfHelloWorld. Sélectionnez OK.

    Capture d’écran de la fenêtre des pages de propriétés kmdfhelloworld avec l’option d’installation du pilote de déploiement sélectionnée.

    Notes

    Dans cet exercice, l’ID matériel n’identifie pas un élément matériel réel. Il identifie un appareil imaginaire qui se verra attribuer une place dans l’arborescence de l’appareil en tant qu’enfant du nœud racine. Pour le matériel réel, ne sélectionnez pas Mise à jour du pilote d’ID matériel. à la place, sélectionnez Installer et vérifier. Vous verrez l’ID matériel dans le fichier d’informations (INF) de votre pilote. Dans la fenêtre Explorateur de solutions, accédez à Fichiers de pilotes KmdfHelloWorld>, puis double-cliquez sur KmdfHelloWorld.inf. L’ID matériel se trouve sous [Standard.NT$ARCH$].

    [Standard.NT$ARCH$]
    %KmdfHelloWorld.DeviceDesc%=KmdfHelloWorld_Device, Root\KmdfHelloWorld
    
  8. Dans le menu Générer , choisissez Déployer la solution. Visual Studio copie automatiquement les fichiers requis pour installer et exécuter le pilote sur l’ordinateur cible. Le déploiement peut prendre une minute ou deux.

    Lorsque vous déployez un pilote, les fichiers de pilote sont copiés dans le dossier %Systemdrive%\drivertest\drivers sur l’ordinateur de test. Si un problème se produit pendant le déploiement, vous pouvez case activée pour voir si les fichiers sont copiés sur l’ordinateur de test. Vérifiez que les fichiers .inf, .cat, test cert et .sys, ainsi que tous les autres fichiers nécessaires, sont présents dans le dossier %systemdrive%\drivertest\drivers.

    Pour plus d’informations sur le déploiement de pilotes, consultez Déploiement d’un pilote sur un ordinateur de test.

Installer le pilote

Une fois votre pilote Hello World déployé sur l’ordinateur cible, vous allez maintenant installer le pilote. Lorsque vous avez précédemment provisionné l’ordinateur cible avec Visual Studio à l’aide de l’option automatique , Visual Studio configure l’ordinateur cible pour exécuter des pilotes signés de test dans le cadre du processus d’approvisionnement. Il vous suffit maintenant d’installer le pilote à l’aide de l’outil DevCon.

  1. Sur l’ordinateur hôte, accédez au dossier Outils dans votre installation WDK et recherchez l’outil DevCon. Par exemple, regardez dans le dossier suivant :

    C :\Program Files (x86)\Windows Kits\10\Tools\x64\devcon.exe

    Copiez l’outil DevCon sur votre ordinateur distant.

  2. Sur l’ordinateur cible, installez le pilote en accédant au dossier contenant les fichiers de pilote, puis en exécutant l’outil DevCon.

    1. Voici la syntaxe générale de l’outil devcon que vous allez utiliser pour installer le pilote :

      devcon installer <l’ID matériel du fichier><INF>

      Le fichier INF requis pour installer ce pilote est KmdfHelloWorld.inf. Le fichier INF contient l’ID matériel pour l’installation du fichier binaire du pilote ,KmdfHelloWorld.sys. Rappelez-vous que l’ID matériel, situé dans le fichier INF, est Root\KmdfHelloWorld.

    2. Ouvrez une fenêtre d’invite de commandes en tant qu’administrateur. Accédez à votre dossier contenant le fichier de .sys de pilote généré et entrez cette commande :

      devcon installez kmdfhelloworld.inf root\kmdfhelloworld

      Si vous recevez un message d’erreur indiquant que devcon n’est pas reconnu, essayez d’ajouter le chemin d’accès à l’outil devcon . Par exemple, si vous l’avez copié dans un dossier appelé C :\Tools sur l’ordinateur cible, essayez d’utiliser la commande suivante :

      c :\tools\devcon install kmdfhelloworld.inf root\kmdfhelloworld

      Une boîte de dialogue s’affiche pour indiquer que le pilote de test est un pilote non signé. Sélectionnez Installer ce pilote quand même pour continuer.

      Capture d’écran de l’avertissement de sécurité affiché pendant le processus d’installation du pilote.

Déboguer le pilote

Maintenant que vous avez installé votre pilote KmdfHelloWorld sur l’ordinateur cible, vous allez attacher un débogueur à distance à partir de l’ordinateur hôte.

  1. Sur l’ordinateur hôte, ouvrez une fenêtre d’invite de commandes en tant qu’administrateur. Accédez au répertoire WinDbg.exe. Nous allons utiliser la version x64 de WinDbg.exe du Kit de pilotes Windows (WDK) qui a été installé dans le cadre de l’installation du Kit Windows. Voici le chemin d’accès par défaut à WinDbg.exe :

    C :\Program Files (x86)\Windows Kits\10\Debuggers\x64

  2. Lancez WinDbg pour vous connecter à une session de débogage du noyau sur l’ordinateur cible à l’aide de la commande suivante. La valeur du port et de la clé doit être la même que celle que vous avez utilisée pour approvisionner l’ordinateur cible. Nous allons utiliser 50000 pour le port et 1.2.3.4 pour la clé, les valeurs que nous avons utilisées pendant l’étape de déploiement. L’indicateur k indique qu’il s’agit d’une session de débogage du noyau.

    WinDbg -k net :port=50000,key=1.2.3.4

  3. Dans le menu Déboguer , choisissez Arrêter. Le débogueur sur l’ordinateur hôte s’arrête sur l’ordinateur cible. Dans la fenêtre Commande du débogueur , vous pouvez voir l’invite de commandes de débogage du noyau : kd>.

  4. À ce stade, vous pouvez tester le débogueur en entrant des commandes à l’invite kd> . Par exemple, vous pouvez essayer les commandes suivantes :

  5. Pour permettre à l’ordinateur cible de s’exécuter à nouveau, choisissez Go dans le menu Déboguer ou appuyez sur « g », puis appuyez sur « Entrée ».

  6. Pour arrêter la session de débogage, choisissez Détacher le débogueur dans le menu Déboguer .

    Important

    Veillez à utiliser la commande « go » pour permettre à l’ordinateur cible de s’exécuter à nouveau avant de quitter le débogueur, sinon l’ordinateur cible ne répond pas à l’entrée de la souris et du clavier, car il parle toujours au débogueur.

Pour obtenir une procédure pas à pas détaillée du processus de débogage du pilote, consultez Déboguer des pilotes universels - Labo pas à pas (Echo Kernel-Mode) .

Pour plus d’informations sur le débogage à distance, consultez Débogage à distance à l’aide de WinDbg.

Outils de débogage pour Windows

Déboguer les pilotes universels - Labo étape par étape (mode noyau Echo)

Écrire votre premier pilote