為不同版本的 Windows 撰寫驅動程式

當您建立驅動程式專案時,您可以指定最低目標操作系統,這是驅動程式將執行的最低 Windows 版本。 例如,您可以指定 Windows 7 是最低目標作業系統。 在此情況下,您的驅動程式會在 Windows 7 和更新版本的 Windows 上執行。

注意

如果您針對特定最低版本的 Windows 開發驅動程式,而且您希望驅動程式在更新版本的 Windows 上運作,則不得使用任何未記載的函式,而且不得以檔描述方式以外的任何方式使用記載的函式。 否則,您的驅動程式可能無法在更新版本的 Windows 上執行。 即使您一直小心只使用記載的函式,您也應該在每次發行時,在新版本的 Windows 上測試您的驅動程式。

僅使用一般功能撰寫多版本驅動程式

當您設計將在多個 Windows 版本上執行的驅動程式時,最簡單的方法是讓驅動程式只使用驅動程式將執行的所有 Windows 版本通用的 DDI 函式和結構。 在此情況下,您會將最低目標操作系統設定為驅動程式將支援的最早 Windows 版本。

例如,若要支援所有版本的 Windows,從 Windows 7 開始,您應該:

  1. 設計和實作驅動程式,使其只使用 Windows 7 中存在的功能。

  2. 當您建置驅動程式時,請將 Windows 7 指定為最低目標作業系統。

雖然此程序很簡單,但它可能會限制驅動程式只使用較新版本 Windows 上可用的功能子集。 在許多情況下,當作業系統功能可供使用時,您會想要使用較新的操作系統功能,以改善安全性、改善可靠性,或啟用較新的功能。

撰寫使用版本相依功能的多重版本驅動程式

內核模式驅動程式可以動態判斷操作系統提供的 API 是否可用,或驅動程式執行所在的 Windows 版本,並選擇使用該運行時間環境中可用的功能。 例如,必須支援所有 Windows 版本的驅動程式,從 Windows 7 開始,可以在運行時間判斷其執行中的 Windows 版本。 如果驅動程式在 Windows 7 上執行,它只能使用 Windows 7 支援的 DDI 函式。 不過,相同的驅動程式可以使用 Windows 8 特有的其他 DDI 函式,例如,當其運行時間檢查判斷這些 API 目前存在或判斷它正在 Windows 8 上執行時。

注意

建議您盡可能檢查功能或 API 可用性,而不是嘗試檢查驅動程式是否在特定作業系統版本或更新版本上執行。

有條件地呼叫 Windows 版本相依函式

內核模式驅動程式可以使用 MmGetSystemRoutineAddress MmGetSystemRoutineAddressEx 函式,動態檢查它想要使用的特定 API 是否可在目前的運行時間環境中使用,並取得要用來呼叫該 API 的函式指標。

注意

為了協助保留類型檢查並防止意外的錯誤,您應該建立一個可鏡像原始函式類型的 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 版本。

注意

建議您盡可能檢查功能或 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.
    //

}
...