Share via


Écriture de pilotes pour différentes versions de Windows

Lorsque vous créez un projet de pilote, vous spécifiez le système d’exploitation cible minimal, qui est la version minimale de Windows sur laquelle votre pilote s’exécutera. Par exemple, vous pouvez spécifier que Windows 7 est le système d’exploitation cible minimal. Dans ce cas, votre pilote s’exécuterait sur Windows 7 et versions ultérieures de Windows.

Remarque

Si vous développez un pilote pour une version minimale particulière de Windows et que vous souhaitez que votre pilote fonctionne sur les versions ultérieures de Windows, vous ne devez pas utiliser de fonctions non documentées, et vous ne devez pas utiliser de fonctions documentées d’une autre manière que celle décrite dans la documentation. Sinon, votre pilote peut échouer à s’exécuter sur les versions ultérieures de Windows. Même si vous avez été prudent d’utiliser uniquement les fonctions documentées, vous devez tester votre pilote sur la nouvelle version de Windows chaque fois qu’un est publié.

Écriture d’un pilote multiversion à l’aide de fonctionnalités courantes uniquement

Lorsque vous concevez un pilote qui s’exécutera sur plusieurs versions de Windows, l’approche la plus simple consiste à permettre au pilote d’utiliser uniquement des fonctions et des structures DDI communes à toutes les versions de Windows sur lesquelles le pilote s’exécutera. Dans ce cas, vous définissez le système d’exploitation cible minimal sur la version la plus ancienne de Windows prise en charge par le pilote.

Par exemple, pour prendre en charge toutes les versions de Windows, à partir de Windows 7, vous devez :

  1. Concevez et implémentez le pilote afin qu’il utilise uniquement les fonctionnalités présentes dans Windows 7.

  2. Lorsque vous générez votre pilote, spécifiez Windows 7 comme système d’exploitation cible minimal.

Bien que ce processus soit simple, il peut restreindre le pilote à utiliser uniquement un sous-ensemble des fonctionnalités disponibles sur les versions ultérieures de Windows. Dans de nombreux cas, vous souhaiterez utiliser des fonctionnalités de système d’exploitation plus récentes lorsqu’elles sont disponibles afin d’améliorer la sécurité, d’améliorer la fiabilité ou d’activer des fonctionnalités plus récentes.

Écriture d’un pilote multiversion qui utilise des fonctionnalités dépendantes de la version

Un pilote en mode noyau peut déterminer dynamiquement si une API fournie par le système d’exploitation est disponible ou quelle version de Windows le pilote est en cours d’exécution et choisir d’utiliser des fonctionnalités disponibles dans cet environnement d’exécution. Par exemple, un pilote qui doit prendre en charge toutes les versions de Windows, à partir de Windows 7, peut déterminer, au moment de l’exécution, la version de Windows sur laquelle elle s’exécute. Si le pilote s’exécute sur Windows 7, il doit utiliser uniquement les fonctions DDI que Windows 7 prend en charge. Toutefois, le même pilote peut utiliser des fonctions DDI supplémentaires qui sont uniques à Windows 8, par exemple, lorsque son case activée d’exécution détermine que ces API sont présentes ou déterminent qu’elles s’exécutent sur Windows 8.

Remarque

Il est recommandé d’case activée pour la disponibilité des fonctionnalités ou des API lorsque cela est possible au lieu d’essayer de case activée si votre pilote s’exécute sur une certaine version du système d’exploitation ou une version ultérieure.

Appel conditionnel des fonctions dépendantes de la version windows

Un pilote en mode noyau peut utiliser les fonctions MmGetSystemRoutineAddress ou MmGetSystemRoutineAddressEx pour case activée dynamiquement si une API particulière qu’elle souhaite utiliser est disponible dans l’environnement d’exécution actuel et pour obtenir un pointeur de fonction à utiliser pour appeler cette API.

Remarque

Pour préserver les case activée de type et empêcher les erreurs involontaires, vous devez créer un typedef qui miroir le type de fonction d’origine.

Exemple : Détermination de la disponibilité de l’API et de l’API d’appel conditionnel

typedef
NTSTATUS
(*PFN_IoOpenDriverRegistryKey)(
    PDRIVER_OBJECT     DriverObject,
    DRIVER_REGKEY_TYPE RegKeyType,
    ACCESS_MASK        DesiredAccess,
    ULONG              Flags,
    PHANDLE            DriverRegKey
    );

VOID ExampleFunction(VOID) {
    NTSTATUS status = STATUS_UNSUCCESSFUL;
    HANDLE persistentStateKey = NULL;
    PFN_IoOpenDriverRegistryKey pfnIoOpenDriverRegistryKey = NULL;
    UNICODE_STRING functionName = {0};

    RtlInitUnicodeString(&functionName, L"IoOpenDriverRegistryKey");
    pfnIoOpenDriverRegistryKey = (PFN_IoOpenDriverRegistryKey)MmGetSystemRoutineAddress(&functionName);

    if (pfnIoOpenDriverRegistryKey != NULL) {
        // Open a key to where state can be stored under the driver service
        status = pfnIoOpenDriverRegistryKey(g_GlobalStructure.DriverObject,
                                            DriverRegKeyPersistentState,
                                            KEY_WRITE,
                                            0,
                                            &persistentStateKey);
    } else {
        // Fall back to opening up a different location to store state in
    }

    // Use the opened registry key
}

Détermination de la version de Windows

Un pilote en mode noyau peut utiliser la fonction RtlVerifyVersionInfo pour case activée dynamiquement la version de Windows sur laquelle elle s’exécute actuellement.

Remarque

Il est recommandé d’case activée pour la disponibilité des fonctionnalités ou des API lorsque cela est possible au lieu d’essayer de case activée si votre pilote s’exécute sur une certaine version du système d’exploitation ou une version ultérieure.

Exemple : détermination de la version de Windows

L’exemple suivant détecte si la version du système d’exploitation en cours d’exécution est supérieure ou égale à la version 10.0 et détecte si le numéro de build est supérieur ou égal à la build 22000 (Windows 11, version 21H2).

...

NTSTATUS Status = STATUS_SUCCESS;
RTL_OSVERSIONINFOEXW VersionInfo = {0};
ULONG TypeMask = 0;
ULONGLONG ConditionMask = 0;

VersionInfo.dwOSVersionInfoSize = sizeof(VersionInfo);
VersionInfo.dwMajorVersion = 10;
VersionInfo.dwMinorVersion = 0;
VersionInfo.dwBuildNumber = 22000;

TypeMask = VER_MAJORVERSION | VER_MINORVERSION | VER_BUILDNUMBER;
VER_SET_CONDITION(ConditionMask, VER_MAJORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_MINORVERSION, VER_GREATER_EQUAL);
VER_SET_CONDITION(ConditionMask, VER_BUILDNUMBER, VER_GREATER_EQUAL);

Status = RtlVerifyVersionInfo(&VersionInfo,
                              TypeMask,
                              ConditionMask);

if (NT_SUCCESS(Status)) {

    //
    // The call to RtlVerifyVersionInfo succeeded, so the running OS
    // version and build number is greater than or equal to the value
    // specified. Do appropriate action for newer OS versions.
    //

} else if (Status == STATUS_REVISION_MISMATCH) {

    //
    // The running OS version is less than the value specified. Do
    // appropriate action for older OS versions.
    //

} else {

    //
    // There was an error comparing to the running OS version. Do
    // appropriate action for when the OS version is not known.
    //

}
...