[PATCH v2 3/3] kernel32: Implement compatibility mode for VerifyVersionInfo.

Gabriel Ivăncescu gabrielopcode at gmail.com
Tue Mar 17 11:07:53 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/version.c | 141 ++++++++++++++++++++++++++++++++++++++--
 1 file changed, 135 insertions(+), 6 deletions(-)

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