Signed-off-by: Gabriel Ivăncescu gabrielopcode@gmail.com ---
This is mostly copied from RtlVerifyVersionInfo, but using GetVersionEx instead of RtlGetVersion. Also, it has slight tweaks to return values, since this API uses SetLastError and a BOOL return value. The behavior should be identical to before, though, except when the compatibility mode kicks in.
dlls/kernel32/tests/version.c | 5 -- dlls/kernel32/version.c | 141 ++++++++++++++++++++++++++++++++-- 2 files changed, 135 insertions(+), 11 deletions(-)
diff --git a/dlls/kernel32/tests/version.c b/dlls/kernel32/tests/version.c index c9e92a9..5fdc961 100644 --- a/dlls/kernel32/tests/version.c +++ b/dlls/kernel32/tests/version.c @@ -193,8 +193,6 @@ static void test_VerifyVersionInfo(void) DWORD condition3; DWORD typemask4; DWORD condition4; - - BOOL todo; } verify_version_tests[] = { { @@ -665,13 +663,10 @@ static void test_VerifyVersionInfo(void)
SetLastError(0xdeadbeef); ret = VerifyVersionInfoA(&info, test->verifymask, mask); - todo_wine_if(test->todo) - { ok(test->err ? !ret : ret, "%u: unexpected return value %d.\n", i, ret); if (!ret) ok(GetLastError() == test->err, "%u: unexpected error code %d, expected %d.\n", i, GetLastError(), test->err); } - }
/* test handling of version numbers */ /* v3.10 is always less than v4.x even diff --git a/dlls/kernel32/version.c b/dlls/kernel32/version.c index 5f33847..0716c29 100644 --- a/dlls/kernel32/version.c +++ b/dlls/kernel32/version.c @@ -42,6 +42,61 @@ WINE_DEFAULT_DEBUG_CHANNEL(ver);
+static inline UCHAR version_update_condition(UCHAR *last_condition, UCHAR condition) +{ + switch (*last_condition) + { + case 0: + *last_condition = condition; + break; + case VER_EQUAL: + if (condition >= VER_EQUAL && condition <= VER_LESS_EQUAL) + { + *last_condition = condition; + return condition; + } + break; + case VER_GREATER: + case VER_GREATER_EQUAL: + if (condition >= VER_EQUAL && condition <= VER_GREATER_EQUAL) + return condition; + break; + case VER_LESS: + case VER_LESS_EQUAL: + if (condition == VER_EQUAL || (condition >= VER_LESS && condition <= VER_LESS_EQUAL)) + return condition; + break; + } + if (!condition) *last_condition |= 0x10; + return *last_condition & 0xf; +} + +static inline BOOL version_compare_values(ULONG left, ULONG right, UCHAR condition) +{ + switch (condition) + { + case VER_EQUAL: + if (left != right) return FALSE; + break; + case VER_GREATER: + if (left <= right) return FALSE; + break; + case VER_GREATER_EQUAL: + if (left < right) return FALSE; + break; + case VER_LESS: + if (left >= right) return FALSE; + break; + case VER_LESS_EQUAL: + if (left > right) return FALSE; + break; + default: + return FALSE; + } + return TRUE; +} + + /****************************************************************************** * VerifyVersionInfoA (KERNEL32.@) */ @@ -71,16 +126,90 @@ BOOL WINAPI VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInfo, DWORD dwTypeMa BOOL WINAPI VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask) { - switch(RtlVerifyVersionInfo( lpVersionInfo, dwTypeMask, dwlConditionMask )) + OSVERSIONINFOEXW ver; + + TRACE("(%p 0x%x 0x%s)\n", lpVersionInfo, dwTypeMask, wine_dbgstr_longlong(dwlConditionMask)); + + ver.dwOSVersionInfoSize = sizeof(ver); + if (!GetVersionExW((OSVERSIONINFOW*)&ver)) return FALSE; + + if (!dwTypeMask || !dwlConditionMask) { - case STATUS_INVALID_PARAMETER: - SetLastError( ERROR_BAD_ARGUMENTS ); - return FALSE; - case STATUS_REVISION_MISMATCH: - SetLastError( ERROR_OLD_WIN_VERSION ); + SetLastError(ERROR_BAD_ARGUMENTS); return FALSE; } + + if (dwTypeMask & VER_PRODUCT_TYPE) + { + if (!version_compare_values(ver.wProductType, lpVersionInfo->wProductType, dwlConditionMask >> 7*3 & 0x07)) + goto mismatch; + } + if (dwTypeMask & VER_SUITENAME) + switch (dwlConditionMask >> 6*3 & 0x07) + { + case VER_AND: + if ((lpVersionInfo->wSuiteMask & ver.wSuiteMask) != lpVersionInfo->wSuiteMask) + goto mismatch; + break; + case VER_OR: + if (!(lpVersionInfo->wSuiteMask & ver.wSuiteMask) && lpVersionInfo->wSuiteMask) + goto mismatch; + break; + default: + SetLastError(ERROR_BAD_ARGUMENTS); + return FALSE; + } + if (dwTypeMask & VER_PLATFORMID) + { + if (!version_compare_values(ver.dwPlatformId, lpVersionInfo->dwPlatformId, dwlConditionMask >> 3*3 & 0x07)) + goto mismatch; + } + if (dwTypeMask & VER_BUILDNUMBER) + { + if (!version_compare_values(ver.dwBuildNumber, lpVersionInfo->dwBuildNumber, dwlConditionMask >> 2*3 & 0x07)) + goto mismatch; + } + + if (dwTypeMask & (VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR | VER_SERVICEPACKMINOR)) + { + unsigned char condition, last_condition = 0; + BOOL succeeded = TRUE, do_next_check = TRUE; + + if (dwTypeMask & VER_MAJORVERSION) + { + condition = version_update_condition(&last_condition, dwlConditionMask >> 1*3 & 0x07); + succeeded = version_compare_values(ver.dwMajorVersion, lpVersionInfo->dwMajorVersion, condition); + do_next_check = (ver.dwMajorVersion == lpVersionInfo->dwMajorVersion) && + ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); + } + if ((dwTypeMask & VER_MINORVERSION) && do_next_check) + { + condition = version_update_condition(&last_condition, dwlConditionMask >> 0*3 & 0x07); + succeeded = version_compare_values(ver.dwMinorVersion, lpVersionInfo->dwMinorVersion, condition); + do_next_check = (ver.dwMinorVersion == lpVersionInfo->dwMinorVersion) && + ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); + } + if ((dwTypeMask & VER_SERVICEPACKMAJOR) && do_next_check) + { + condition = version_update_condition(&last_condition, dwlConditionMask >> 5*3 & 0x07); + succeeded = version_compare_values(ver.wServicePackMajor, lpVersionInfo->wServicePackMajor, condition); + do_next_check = (ver.wServicePackMajor == lpVersionInfo->wServicePackMajor) && + ((condition >= VER_EQUAL) && (condition <= VER_LESS_EQUAL)); + } + if ((dwTypeMask & VER_SERVICEPACKMINOR) && do_next_check) + { + condition = version_update_condition(&last_condition, dwlConditionMask >> 4*3 & 0x07); + succeeded = version_compare_values(ver.wServicePackMinor, lpVersionInfo->wServicePackMinor, condition); + } + + if (!succeeded) goto mismatch; + } + return TRUE; + +mismatch: + SetLastError(ERROR_OLD_WIN_VERSION); + return FALSE; }
/***********************************************************************