[PATCH v3 5/5] kernel32: Implement compatibility mode for VerifyVersionInfo.
Gabriel Ivăncescu
gabrielopcode at gmail.com
Wed Mar 18 11:31:55 CDT 2020
Signed-off-by: Gabriel Ivăncescu <gabrielopcode at 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;
}
/***********************************************************************
--
2.21.0
More information about the wine-devel
mailing list