Driver won't load on Windows 2000? VER_SET_CONDITION may be the culprit

On Microsoft Windows XP and later versions of Windows, drivers can call RtlVerifyVersionInfo to compare a specified set of operating system version requirements to the corresponding attributes of the currently running version of the operating system. The VER_SET_CONDITION macro is used to create a condition mask that specifies how to compare the version requirements. The condition mask is used as an input parameter to RtlVerifyVersionInfo.

Unfortunately, VER_SET_CONDITION causes an unresolved import in drivers built for Windows XP and later that attempt to load on Windows 2000 systems. Why? Because the VER_SET_CONDITION macro defined in Ntddk.h calls the VerSetConditionMask function, which is not exposed by Ntoskrnl.exe on Windows 2000.

The linker cannot find this unresolved import at link time if the driver is built with Ntoskrnl.lib for Windows XP or later because VerSetConditionMask is exported by that version of the library. Instead, when the driver is loaded on a system running Windows 2000 and the memory manager tries to resolve imports called by the driver, it fails to find VerSetConditionMask in Ntoskrnl.exe. The driver image fails to load and Device Manager reports error code 31 (CM_PROB_FAILED_ADD).

What should you do?

If you are building a single driver binary to run on Windows 2000, Windows XP, and later versions of Windows, and wish to use RtlVerifyVersionInfo in your driver, here's how to avoid the unresolved import caused by VER_SET_CONDITION:

Use MmGetSystemRoutineAddress to determine whether the RtlVerifyVersionInfo function is available on the currently running version of Windows.

If RtlVerifyVersionInfo is not available, assume you are running on Windows 2000 and use PsGetVersion to get information about the current version of the OS. (Note that PsGetVersion is deprecated for Windows XP and later versions of Windows.)

The following code sample shows how to use MmGetSystemRoutineAddress to test for availability of RtlVerifyVersionInfo.

typedef
ULONGLONG
(*PFN_VER_SET_CONDITION_MASK)(
		IN  ULONGLONG   ConditionMask,
		IN  ULONG   TypeMask,
		IN  UCHAR   Condition
		);

typedef
NTSTATUS
(*PFN_RTL_VERIFY_VERSION_INFO)(
		IN PRTL_OSVERSIONINFOEXW VersionInfo,
		IN ULONG TypeMask,
		IN ULONGLONG  ConditionMask
		);

VOID
MyDriverVerifyVersion(
		VOID
		)
{
		UNICODE_STRING funcName;
		RTL_OSVERSIONINFOEXW info;
		PFN_RTL_VERIFY_VERSION_INFO pRtlVerifyVersionInfo;
		PFN_VER_SET_CONDITION_MASK pVerSetConditionMask;
		ULONGLONG condition;
		NTSTATUS status;

		RtlInitUnicodeString(&funcName, L"RtlVerifyVersionInfo");
		pRtlVerifyVersionInfo = (PFN_RTL_VERIFY_VERSION_INFO)
				MmGetSystemRoutineAddress(&funcName);

		if (pRtlVerifyVersionInfo == NULL) {
			// We are on Win2K-- guaranteed not to be XP or later.
			// Do win2k specific checks here
			// To check the specific SP number, either parse the
			// CSDVersion returned by PsGetVersion or use a user mode
			// application to report the service pack number to 
			// the driver. See PsGetVersion in the DDK documentation 
			// for more information.

			return; 
		}

		// If RtlVerifyVersionInfo is present, 
		// assume VerSetConditionMask is present as well
		RtlInitUnicodeString(&funcName, L"VerSetConditionMask");
		pVerSetConditionMask = (PFN_VER_SET_CONDITION_MASK)
				MmGetSystemRoutineAddress(&funcName);

		// This code checks for XP Gold or XP SP1

		// Check for XP
		condition = 0;
		RtlZeroMemory(&info, sizeof(info));
		info.dwOSVersionInfoSize = sizeof(info);

		info.dwMajorVersion = 5;
		info.dwMinorVersion = 1;
		condition = pVerSetConditionMask(condition, VER_MAJORVERSION, VER_EQUAL);
		condition = pVerSetConditionMask(condition, VER_MINORVERSION, VER_EQUAL);

		// Check for XP gold and SP1 by checking for less than SP2
		info.wServicePackMajor = 2;
		condition = pVerSetConditionMask(condition, VER_SERVICEPACKMAJOR, VER_LESS);

		status = pRtlVerifyVersionInfo(&info,
							VER_MAJORVERSION |
							VER_MINORVERSION |
							VER_SERVICEPACKMAJOR,
							condition);

	if (NT_SUCCESS(status)) {
		// this is XP Gold or SP1
	}
	else {
		// this is XP SP2 or later OR
		// this is another OS released after XP 
		// such as Windows Server 2003
	}

For more information:

Windows DDK
RtlVerifyVersionInfo
MmGetSystemRoutineAddress
PSGetVersion



Was This Information Useful?