为不同版本的 Windows 编写驱动程序

创建驱动程序项目时,请指定最低目标操作系统,该操作系统是运行驱动程序的 Windows 的最低版本。 例如,可以指定 Windows 7 为最低目标操作系统。 在这种情况下,驱动程序会在 Windows 7 和更高版本的 Windows 上运行。

注意

如果为特定的最低版本的 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 函数。 但是,同一个驱动程序可以使用 Windows 8 独有的其他 DDI 函数,例如,当其运行时检查确定这些 API 当前存在,或者确定它在 Windows 8 上运行时。

注意

建议尽可能检查功能或 API 可用性,而不是尝试检查驱动程序是否在特定操作系统版本或更高版本上运行。

有条件地调用与 Windows 版本相关的函数

内核模式驱动程序可以使用 MmGetSystemRoutineAddressMmGetSystemRoutineAddressEx 函数动态检查它想要使用的特定 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.
    //

}
...