It's only a partial implementation as I'm lacking a) the proper Windows versions and b) a compiler I can trust to finish the testing needed on Windows to fully implement VVI{A,W}. In particular, almost every call I made to VVI ended up with a ERROR_BAD_ARGUMENTS, even when trying MSDN's code or very basic things (like MajorVersion == 5). I was using a pointer to the actual function (got by GetProcAddressA) since the .lib I used (VC98 and mingw) lack it, and that may cause harm since the third argument is a 64bit value instead of a 32bit value like most of the rest. If somebody wants to check it, I have a little program I developped that I can post. Changelog: - Partial implementation of VerifyVersionInfo{A,W}. Vincent
diff -urN wine-orig/dlls/kernel/kernel32.spec wine-pas-compilé/dlls/kernel/kernel32.spec --- wine-orig/dlls/kernel/kernel32.spec Tue May 14 17:13:54 2002 +++ wine-pas-compilé/dlls/kernel/kernel32.spec Thu May 16 22:16:32 2002 @@ -963,7 +963,8 @@ @ stdcall GetCalendarInfoW(long long long ptr long ptr) GetCalendarInfoW @ stdcall SetCalendarInfoA(long long long str) SetCalendarInfoA @ stdcall SetCalendarInfoW(long long long wstr) SetCalendarInfoW -@ stdcall VerifyVersionInfoW(long long long long)VerifyVersionInfoW +@ stdcall VerifyVersionInfoA(long long long long) VerifyVersionInfoA +@ stdcall VerifyVersionInfoW(long long long long) VerifyVersionInfoW # XP extensions @ stdcall DebugActiveProcessStop(long) DebugActiveProcessStop diff -urN wine-orig/include/winbase.h wine-pas-compilé/include/winbase.h --- wine-orig/include/winbase.h Tue May 21 19:11:08 2002 +++ wine-pas-compilé/include/winbase.h Sat May 18 14:46:16 2002 @@ -874,6 +874,10 @@ #define VER_SET_CONDITION(_m_,_t_,_c_) ((_m_)=VerSetConditionMask((_m_),(_t_),(_c_))) +BOOL WINAPI VerifyVersionInfoA(LPOSVERSIONINFOEXA,DWORD,DWORDLONG); +BOOL WINAPI VerifyVersionInfoW(LPOSVERSIONINFOEXW,DWORD,DWORDLONG); +#define VerifyVersionInfo WINELIB_NAME_AW(VerifyVersionInfo) + #define VER_PLATFORM_WIN32s 0 #define VER_PLATFORM_WIN32_WINDOWS 1 #define VER_PLATFORM_WIN32_NT 2 diff -urN wine-orig/misc/version.c wine-pas-compilé/misc/version.c --- wine-orig/misc/version.c Fri May 10 08:40:01 2002 +++ wine-pas-compilé/misc/version.c Wed May 22 23:47:21 2002 @@ -55,7 +55,7 @@ { LONG getVersion16; LONG getVersion32; - OSVERSIONINFOA getVersionEx; + OSVERSIONINFOEXA getVersionEx; } VERSION_DATA; /* FIXME: compare values below with original and fix */ @@ -67,7 +67,8 @@ MAKELONG( 0x0003, 0x8000 ), { sizeof(OSVERSIONINFOA), 2, 0, 0, - VER_PLATFORM_WIN32s, "Win32s 1.3" + VER_PLATFORM_WIN32s, "Win32s 1.3", + 0, 0, 0, 0, 0 } }, /* WIN30 FIXME: verify values */ @@ -76,7 +77,8 @@ MAKELONG( 0x0003, 0x8000 ), { sizeof(OSVERSIONINFOA), 3, 0, 0, - VER_PLATFORM_WIN32s, "Win32s 1.3" + VER_PLATFORM_WIN32s, "Win32s 1.3", + 0, 0, 0, 0, 0 } }, /* WIN31 */ @@ -85,7 +87,8 @@ MAKELONG( 0x0a03, 0x8000 ), { sizeof(OSVERSIONINFOA), 3, 10, 0, - VER_PLATFORM_WIN32s, "Win32s 1.3" + VER_PLATFORM_WIN32s, "Win32s 1.3", + 0, 0, 0, 0, 0 } }, /* WIN95 */ @@ -103,7 +106,8 @@ * http://support.microsoft.com/support/kb/articles/q158/2/38.asp */ sizeof(OSVERSIONINFOA), 4, 0, 0x40003B6, - VER_PLATFORM_WIN32_WINDOWS, "" + VER_PLATFORM_WIN32_WINDOWS, "", + 0, 0, 0, 0, 0 } }, /* WIN98 */ @@ -115,7 +119,8 @@ * Win98SE: 4, 10, 0x40A08AE, " A " */ sizeof(OSVERSIONINFOA), 4, 10, 0x40A07CE, - VER_PLATFORM_WIN32_WINDOWS, " " + VER_PLATFORM_WIN32_WINDOWS, " ", + 0, 0, 0, 0, 0 } }, /* WINME */ @@ -124,7 +129,8 @@ 0xC0005A04, { sizeof(OSVERSIONINFOA), 4, 90, 0x45A0BB8, - VER_PLATFORM_WIN32_WINDOWS, " " + VER_PLATFORM_WIN32_WINDOWS, " ", + 0, 0, 0, 0, 0 } }, /* NT351 */ @@ -133,7 +139,8 @@ 0x04213303, { sizeof(OSVERSIONINFOA), 3, 51, 0x421, - VER_PLATFORM_WIN32_NT, "Service Pack 2" + VER_PLATFORM_WIN32_NT, "Service Pack 2", + 0, 0, 0, 0, 0 } }, /* NT40 */ @@ -142,7 +149,8 @@ 0x05650004, { sizeof(OSVERSIONINFOA), 4, 0, 0x565, - VER_PLATFORM_WIN32_NT, "Service Pack 6" + VER_PLATFORM_WIN32_NT, "Service Pack 6", + 6, 0, 0, VER_NT_WORKSTATION, 0 } }, /* NT2K */ @@ -151,7 +159,8 @@ 0x08930005, { sizeof(OSVERSIONINFOA), 5, 0, 0x893, - VER_PLATFORM_WIN32_NT, "Service Pack 2" + VER_PLATFORM_WIN32_NT, "Service Pack 2", + 2, 0, 0, VER_NT_WORKSTATION, 30 /* FIXME: Great, a reserved field with a value! */ } }, /* WINXP */ @@ -160,7 +169,8 @@ 0x0A280105, { sizeof(OSVERSIONINFOA), 5, 1, 0xA28, - VER_PLATFORM_WIN32_NT, "" + VER_PLATFORM_WIN32_NT, "", + 0, 0, 0, VER_NT_WORKSTATION, 0 /* FIXME: Verify last 5 values */ } } }; @@ -472,10 +482,14 @@ BOOL WINAPI GetVersionExA(OSVERSIONINFOA *v) { WINDOWS_VERSION ver = VERSION_GetVersion(); - if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFOA)) + LPOSVERSIONINFOEXA vex; + + if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) && + v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA)) { - WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d)\n", - v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOA)); + WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n", + v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOA), + sizeof(OSVERSIONINFOEXA)); SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } @@ -484,6 +498,13 @@ v->dwBuildNumber = VersionData[ver].getVersionEx.dwBuildNumber; v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId; strcpy( v->szCSDVersion, VersionData[ver].getVersionEx.szCSDVersion ); + if(v->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXA)) { + vex = (LPOSVERSIONINFOEXA) v; + vex->wServicePackMajor = VersionData[ver].getVersionEx.wServicePackMajor; + vex->wServicePackMinor = VersionData[ver].getVersionEx.wServicePackMinor; + vex->wSuiteMask = VersionData[ver].getVersionEx.wSuiteMask; + vex->wProductType = VersionData[ver].getVersionEx.wProductType; + } return TRUE; } @@ -494,11 +515,14 @@ BOOL WINAPI GetVersionExW(OSVERSIONINFOW *v) { WINDOWS_VERSION ver = VERSION_GetVersion(); + LPOSVERSIONINFOEXW vex; - if (v->dwOSVersionInfoSize < sizeof(OSVERSIONINFOW)) + if (v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) && + v->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW)) { - WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d)\n", - v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOW)); + WARN("wrong OSVERSIONINFO size from app (got: %ld, expected: %d or %d)\n", + v->dwOSVersionInfoSize, sizeof(OSVERSIONINFOW), + sizeof(OSVERSIONINFOEXW)); SetLastError(ERROR_INSUFFICIENT_BUFFER); return FALSE; } @@ -508,19 +532,276 @@ v->dwPlatformId = VersionData[ver].getVersionEx.dwPlatformId; MultiByteToWideChar( CP_ACP, 0, VersionData[ver].getVersionEx.szCSDVersion, -1, v->szCSDVersion, sizeof(v->szCSDVersion)/sizeof(WCHAR) ); + if(v->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW)) { + vex = (LPOSVERSIONINFOEXW) v; + vex->wServicePackMajor = VersionData[ver].getVersionEx.wServicePackMajor; + vex->wServicePackMinor = VersionData[ver].getVersionEx.wServicePackMinor; + vex->wSuiteMask = VersionData[ver].getVersionEx.wSuiteMask; + vex->wProductType = VersionData[ver].getVersionEx.wProductType; + } return TRUE; } +/****************************************************************************** + * VerifyVersionInfoA (KERNEL32.@) + */ +BOOL WINAPI VerifyVersionInfoA( LPOSVERSIONINFOEXA lpVersionInfo, DWORD dwTypeMask, + DWORDLONG dwlConditionMask) +{ + OSVERSIONINFOEXW verW; + + verW.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + verW.dwMajorVersion = lpVersionInfo->dwMajorVersion; + verW.dwMinorVersion = lpVersionInfo->dwMinorVersion; + verW.dwBuildNumber = lpVersionInfo->dwBuildNumber; + verW.dwPlatformId = lpVersionInfo->dwPlatformId; + verW.wServicePackMajor = lpVersionInfo->wServicePackMajor; + verW.wServicePackMinor = lpVersionInfo->wServicePackMinor; + verW.wSuiteMask = lpVersionInfo->wSuiteMask; + verW.wProductType = lpVersionInfo->wProductType; + verW.wReserved = lpVersionInfo->wReserved; + + return VerifyVersionInfoW(&verW, dwTypeMask, dwlConditionMask); +} + /****************************************************************************** * VerifyVersionInfoW (KERNEL32.@) */ -BOOL WINAPI VerifyVersionInfoW( /* LPOSVERSIONINFOEXW */ LPVOID lpVersionInfo, DWORD dwTypeMask, +BOOL WINAPI VerifyVersionInfoW( LPOSVERSIONINFOEXW lpVersionInfo, DWORD dwTypeMask, DWORDLONG dwlConditionMask) { - FIXME("%p %lu %llx\n", lpVersionInfo, dwTypeMask, dwlConditionMask); - return TRUE; + OSVERSIONINFOEXW ver; + BOOL res, error_set; + + FIXME("(%p,%lu,%llx): Not all cases correctly implemented yet\n", lpVersionInfo, dwTypeMask, dwlConditionMask); + /* FIXME: + - Check the following special case on Windows (various versions): + o lp->wSuiteMask == 0 and ver.wSuiteMask != 0 and VER_AND/VER_OR + o lp->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW) + - MSDN talks about some tests being impossible. Check what really happens. + */ + + ver.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEXW); + if(!GetVersionExW((LPOSVERSIONINFOW) &ver)) + return FALSE; + + res = TRUE; + error_set = FALSE; + if(!(dwTypeMask && dwlConditionMask)) { + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_PRODUCT_TYPE) + switch(dwlConditionMask >> 7*3 & 0x07) { + case VER_EQUAL: + if(ver.wProductType != lpVersionInfo->wProductType) + res = FALSE; + break; + case VER_GREATER: + if(ver.wProductType <= lpVersionInfo->wProductType) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.wProductType < lpVersionInfo->wProductType) + res = FALSE; + break; + case VER_LESS: + if(ver.wProductType >= lpVersionInfo->wProductType) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.wProductType > lpVersionInfo->wProductType) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_SUITENAME && res) + switch(dwlConditionMask >> 6*3 & 0x07) { + case VER_AND: + if((lpVersionInfo->wSuiteMask & ver.wSuiteMask) != lpVersionInfo->wSuiteMask) + res = FALSE; + break; + case VER_OR: + if(!(lpVersionInfo->wSuiteMask & ver.wSuiteMask) && lpVersionInfo->wSuiteMask) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_PLATFORMID && res) + switch(dwlConditionMask >> 3*3 & 0x07) { + case VER_EQUAL: + if(ver.dwPlatformId != lpVersionInfo->dwPlatformId) + res = FALSE; + break; + case VER_GREATER: + if(ver.dwPlatformId <= lpVersionInfo->dwPlatformId) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.dwPlatformId < lpVersionInfo->dwPlatformId) + res = FALSE; + break; + case VER_LESS: + if(ver.dwPlatformId >= lpVersionInfo->dwPlatformId) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.dwPlatformId > lpVersionInfo->dwPlatformId) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_BUILDNUMBER && res) + switch(dwlConditionMask >> 2*3 & 0x07) { + case VER_EQUAL: + if(ver.dwBuildNumber != lpVersionInfo->dwBuildNumber) + res = FALSE; + break; + case VER_GREATER: + if(ver.dwBuildNumber <= lpVersionInfo->dwBuildNumber) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.dwBuildNumber < lpVersionInfo->dwBuildNumber) + res = FALSE; + break; + case VER_LESS: + if(ver.dwBuildNumber >= lpVersionInfo->dwBuildNumber) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.dwBuildNumber > lpVersionInfo->dwBuildNumber) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_MAJORVERSION && res) + switch(dwlConditionMask >> 1*3 & 0x07) { + case VER_EQUAL: + if(ver.dwMajorVersion != lpVersionInfo->dwMajorVersion) + res = FALSE; + break; + case VER_GREATER: + if(ver.dwMajorVersion <= lpVersionInfo->dwMajorVersion) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.dwMajorVersion < lpVersionInfo->dwMajorVersion) + res = FALSE; + break; + case VER_LESS: + if(ver.dwMajorVersion >= lpVersionInfo->dwMajorVersion) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.dwMajorVersion > lpVersionInfo->dwMajorVersion) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_MINORVERSION && res) + switch(dwlConditionMask >> 0*3 & 0x07) { + case VER_EQUAL: + if(ver.dwMinorVersion != lpVersionInfo->dwMinorVersion) + res = FALSE; + break; + case VER_GREATER: + if(ver.dwMinorVersion <= lpVersionInfo->dwMinorVersion) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.dwMinorVersion < lpVersionInfo->dwMinorVersion) + res = FALSE; + break; + case VER_LESS: + if(ver.dwMinorVersion >= lpVersionInfo->dwMinorVersion) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.dwMinorVersion > lpVersionInfo->dwMinorVersion) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_SERVICEPACKMAJOR && res) + switch(dwlConditionMask >> 5*3 & 0x07) { + case VER_EQUAL: + if(ver.wServicePackMajor != lpVersionInfo->wServicePackMajor) + res = FALSE; + break; + case VER_GREATER: + if(ver.wServicePackMajor <= lpVersionInfo->wServicePackMajor) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.wServicePackMajor < lpVersionInfo->wServicePackMajor) + res = FALSE; + break; + case VER_LESS: + if(ver.wServicePackMajor >= lpVersionInfo->wServicePackMajor) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.wServicePackMajor > lpVersionInfo->wServicePackMajor) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + if(dwTypeMask & VER_SERVICEPACKMINOR && res) + switch(dwlConditionMask >> 4*3 & 0x07) { + case VER_EQUAL: + if(ver.wServicePackMinor != lpVersionInfo->wServicePackMinor) + res = FALSE; + break; + case VER_GREATER: + if(ver.wServicePackMinor <= lpVersionInfo->wServicePackMinor) + res = FALSE; + break; + case VER_GREATER_EQUAL: + if(ver.wServicePackMinor < lpVersionInfo->wServicePackMinor) + res = FALSE; + break; + case VER_LESS: + if(ver.wServicePackMinor >= lpVersionInfo->wServicePackMinor) + res = FALSE; + break; + case VER_LESS_EQUAL: + if(ver.wServicePackMinor > lpVersionInfo->wServicePackMinor) + res = FALSE; + break; + default: + res = FALSE; + SetLastError(ERROR_BAD_ARGUMENTS); + error_set = TRUE; + } + + if(!(res || error_set)) + SetLastError(ERROR_OLD_WIN_VERSION); + return res; }