Scrittura di driver per versioni diverse di Windows

Quando crei un progetto driver, specifichi il sistema operativo di destinazione minimo, ovvero la versione minima di Windows su cui verrà eseguito il driver. Ad esempio, è possibile specificare che Windows 7 è il sistema operativo di destinazione minimo. In tal caso, il driver verrebbe eseguito in Windows 7 e versioni successive di Windows.

Nota

Se si sviluppa un driver per una determinata versione minima di Windows e si vuole che il driver funzioni nelle versioni successive di Windows, non è necessario usare funzioni non documentate e non è necessario usare funzioni documentate in alcun modo diverso da come viene descritto nella documentazione. In caso contrario, l'esecuzione del driver potrebbe non riuscire nelle versioni successive di Windows. Anche se sei stato attento a usare solo funzioni documentate, dovresti testare il driver nella nuova versione di Windows ogni volta che ne viene rilasciata una.

Scrittura di un driver con più versioni usando solo le funzionalità comuni

Quando si progetta un driver che verrà eseguito su più versioni di Windows, l'approccio più semplice consiste nel consentire al driver di usare solo funzioni e strutture DDI comuni a tutte le versioni di Windows in cui verrà eseguito il driver. In questo caso, imposti il sistema operativo di destinazione minimo sulla versione meno recente di Windows supportata dal driver.

Ad esempio, per supportare tutte le versioni di Windows, a partire da Windows 7, è necessario:

  1. Progettare e implementare il driver in modo che usi solo le funzionalità presenti in Windows 7.

  2. Quando si compila il driver, specificare Windows 7 come sistema operativo di destinazione minimo.

Anche se questo processo è semplice, potrebbe limitare l'uso del driver solo di un subset delle funzionalità disponibili nelle versioni successive di Windows. In molti casi, è consigliabile usare le funzionalità più recenti del sistema operativo quando è disponibile per migliorare la sicurezza, migliorare l'affidabilità o abilitare le funzionalità più recenti.

Scrittura di un driver con più versioni che usa funzionalità dipendenti dalla versione

Un driver in modalità kernel può determinare in modo dinamico se un'API fornita dal sistema operativo è disponibile o quale versione di Windows il driver è in esecuzione e scegliere di usare le funzionalità disponibili in tale ambiente di runtime. Ad esempio, un driver che deve supportare tutte le versioni di Windows, a partire da Windows 7, può determinare, in fase di esecuzione, la versione di Windows in cui è in esecuzione. Se il driver è in esecuzione in Windows 7, deve usare solo le funzioni DDI supportate da Windows 7. Tuttavia, lo stesso driver può usare funzioni DDI aggiuntive univoche per Windows 8, ad esempio, quando il controllo della fase di esecuzione determina che tali API sono attualmente presenti o determinano che è in esecuzione in Windows 8.

Nota

È consigliabile verificare la disponibilità di funzionalità o API quando possibile anziché provare a verificare se il driver è in esecuzione in una determinata versione del sistema operativo o versione successiva.

Chiamata condizionale di funzioni dipendenti dalla versione di Windows

Un driver in modalità kernel può usare le funzioni MmGetSystemRoutineAddress o MmGetSystemRoutineAddressEx per controllare in modo dinamico se un'API specifica che vuole usare è disponibile nell'ambiente di runtime corrente e per ottenere un puntatore di funzione da usare per chiamare tale API.

Nota

Per mantenere il controllo dei tipi e prevenire errori non intenzionali, è necessario creare un typedef che rispecchia il tipo di funzione originale.

Esempio: Determinazione della disponibilità dell'API e chiamata condizionale dell'API

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
}

Determinazione della versione di Windows

Un driver in modalità kernel può usare la funzione RtlVerifyVersionInfo per controllare in modo dinamico la versione di Windows in cui è attualmente in esecuzione.

Nota

È consigliabile verificare la disponibilità di funzionalità o API quando possibile anziché provare a verificare se il driver è in esecuzione in una determinata versione del sistema operativo o versione successiva.

Esempio: Determinazione della versione di Windows

L'esempio seguente rileva se la versione del sistema operativo attualmente in esecuzione è maggiore o uguale alla versione 10.0 e rileva se il numero di build è maggiore o uguale alla build 22000 (Windows 11, versione 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.
    //

}
...