異なるバージョンの Windows に対するドライバーの作成

ドライバー プロジェクトを作成するときに、ドライバーを実行する Windows の最小バージョンである最小ターゲット オペレーティング システムを指定します。 たとえば、Windows 7 が最小ターゲット オペレーティング システムであることを指定できます。 その場合、ドライバーは Windows 7 以降のバージョンの Windows で実行されます。

Note

ある最低バージョンの Windows に向けてドライバーを開発する場合、そのドライバーを以降のバージョンの Windows で動作させたいときは、文書化されていない関数を使うことはできません。また、文書化されている関数であっても、ドキュメントに記載されていない方法で使うことはできません。 そうしないと、ドライバーが新しいバージョンの Windows で実行できない可能性があります。 文書化された関数のみを使用するように注意した場合でも、リリースされるたびに新しいバージョンの Windows でドライバーをテストする必要があります。

共通の機能のみを使ったマルチバージョン ドライバーの作成

複数のバージョンの Windows で実行されるドライバーを設計する場合、最も簡単な方法は、ドライバーが実行されるすべてのバージョンの Windows に共通する DDI 関数と構造体のみを使用できるようにすることです。 この状況では、ドライバーがサポートする最も古いバージョンの Windows に最小ターゲット オペレーティング システムを設定します。

たとえば、Windows 7 以降のすべてのバージョンの Windows をサポートするには、次の手順を実行する必要があります。

  1. Windows 7 に存在する機能のみを使用するようにドライバーを設計して実装します。

  2. ドライバーをビルドするときは、最小ターゲット オペレーティング システムとして Windows 7 を指定します。

このプロセスは単純ですが、ドライバーは、新しいバージョンの Windows で使用できる機能のサブセットのみを使用するように制限する場合があります。 多くの場合、セキュリティの向上、信頼性の向上、またはより新しい機能の有効化のために、より新しいオペレーティング システム機能を使用可能になったときに使用する必要があります。

特定バージョンに依存する機能を使ったマルチバージョン ドライバーの作成

カーネルモードのドライバーでは、オペレーティング システムによって提供される API が利用できるかどうかや、どのバージョンの Windows でドライバーが実行されているかを動的に判断したり、そのランタイム環境で使用できる機能を使用することを選択したりできます。 たとえば、Windows 7 以降のすべてのバージョンの Windows をサポートする必要があるドライバーは、実行時に実行されている Windows のバージョンを決定できます。 ドライバーが Windows 7 で実行されている場合は、Windows 7 でサポートされている DDI 関数のみを使用する必要があります。 ただし、たとえば、ドライバーの実行時チェックにより、現在それらの API が存在すると判断されたり、Windows 8 で動作中であると判断された場合は、Windows 8 に固有の追加 DDI 関数も同じドライバーで使うことができます。

Note

ドライバーが特定のバージョン以降のオペレーティング システムで実行されているかどうかを確認するのではなく、可能な場合には常に機能または API の可用性を確認することをお勧めします。

Windows バージョンに依存する関数の条件付き呼び出し

カーネルモードのドライバーでは、MmGetSystemRoutineAddress または MmGetSystemRoutineAddressEx 関数を使用して、使用される特定の API が現在のランタイム環境で使用できるかどうかを動的に確認し、その API を呼び出すために使用する関数ポインターを取得できます。

Note

型チェックの結果を維持し、意図しないエラーを防ぐために、元の関数の型をミラー化した typedef を作る必要があります。

例: API の可用性を判断して 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
}

Windows バージョンの特定

カーネル モード ドライバーは、RtlVerifyVersionInfo 関数を使用して、現在実行されている Windows のバージョンを動的にチェックできます。

Note

ドライバーが特定のバージョン以降のオペレーティング システムで実行されているかどうかを確認するのではなく、可能な場合には常に機能または API の可用性を確認することをお勧めします。

例: Windows のバージョンの決定

次の例では、現在実行中のオペレーティング システムのバージョンがバージョン 10.0 以上かどうかを検出し、ビルド番号がビルド 22000 (Windows 11 バージョン 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.
    //

}
...