kernelbase: Implement compatibility mode for GetVersionEx.
Since Windows 8.1, these functions have been deprecated and run in a sort of compatibility mode, reporting Windows 8 unless the application supplies a manifest that specifies compatibility with newer Windows versions explicitly (by listing their GUIDs). Some applications have bad non-forward-compatible checks based on GetVersionEx, and depend on this behavior (they do not supply a manifest). Currently, they break on Wine if we use a Windows 10 prefix for example, since we always report the real version. One example is the game Rock of Ages. Signed-off-by: Gabriel Ivăncescu <gabrielopcode@gmail.com> Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
e95d0813fd
commit
6719bf2e03
|
@ -610,7 +610,7 @@ static void test_VerifyVersionInfo(void)
|
||||||
|
|
||||||
if (rtlinfo.dwMajorVersion != 6 || rtlinfo.dwMinorVersion != 2)
|
if (rtlinfo.dwMajorVersion != 6 || rtlinfo.dwMinorVersion != 2)
|
||||||
{
|
{
|
||||||
win_skip("GetVersionEx and VerifyVersionInfo are faking values\n");
|
skip("GetVersionEx and VerifyVersionInfo are faking values\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,8 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "ntstatus.h"
|
||||||
|
#define WIN32_NO_STATUS
|
||||||
#define NONAMELESSUNION
|
#define NONAMELESSUNION
|
||||||
#define NONAMELESSSTRUCT
|
#define NONAMELESSSTRUCT
|
||||||
#include "windef.h"
|
#include "windef.h"
|
||||||
|
@ -60,6 +62,13 @@ typedef struct
|
||||||
DWORD resloader;
|
DWORD resloader;
|
||||||
} NE_TYPEINFO;
|
} NE_TYPEINFO;
|
||||||
|
|
||||||
|
struct version_info
|
||||||
|
{
|
||||||
|
DWORD major;
|
||||||
|
DWORD minor;
|
||||||
|
DWORD build;
|
||||||
|
};
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* Version Info Structure
|
* Version Info Structure
|
||||||
*/
|
*/
|
||||||
|
@ -116,6 +125,114 @@ typedef struct
|
||||||
(VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
|
(VS_VERSION_INFO_STRUCT32 *)( (LPBYTE)ver + (((ver)->wLength + 3) & ~3) )
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* Win8 info, reported if app doesn't provide compat GUID in manifest.
|
||||||
|
*/
|
||||||
|
static const struct version_info windows8_version_info = { 6, 2, 0x23f0 };
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* Windows versions that need compatibility GUID specified in manifest
|
||||||
|
* in order to be reported by the APIs.
|
||||||
|
*/
|
||||||
|
static const struct
|
||||||
|
{
|
||||||
|
struct version_info info;
|
||||||
|
GUID guid;
|
||||||
|
} version_data[] =
|
||||||
|
{
|
||||||
|
/* Windows 8.1 */
|
||||||
|
{
|
||||||
|
{ 6, 3, 0x2580 },
|
||||||
|
{0x1f676c76,0x80e1,0x4239,{0x95,0xbb,0x83,0xd0,0xf6,0xd0,0xda,0x78}}
|
||||||
|
},
|
||||||
|
/* Windows 10 */
|
||||||
|
{
|
||||||
|
{ 10, 0, 0x42ee },
|
||||||
|
{0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/******************************************************************************
|
||||||
|
* init_current_version
|
||||||
|
*
|
||||||
|
* Initialize the current_version variable.
|
||||||
|
*
|
||||||
|
* For compatibility, Windows 8.1 and later report Win8 version unless the app
|
||||||
|
* has a manifest that confirms its compatibility with newer versions of Windows.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
static RTL_OSVERSIONINFOEXW current_version;
|
||||||
|
|
||||||
|
static BOOL CALLBACK init_current_version(PINIT_ONCE init_once, PVOID parameter, PVOID *context)
|
||||||
|
{
|
||||||
|
/*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci;
|
||||||
|
const struct version_info *ver;
|
||||||
|
SIZE_T req;
|
||||||
|
int idx;
|
||||||
|
|
||||||
|
current_version.dwOSVersionInfoSize = sizeof(current_version);
|
||||||
|
if (!set_ntstatus( RtlGetVersion(¤t_version) )) return FALSE;
|
||||||
|
|
||||||
|
for (idx = ARRAY_SIZE(version_data); idx--;)
|
||||||
|
if ( current_version.dwMajorVersion > version_data[idx].info.major ||
|
||||||
|
(current_version.dwMajorVersion == version_data[idx].info.major &&
|
||||||
|
current_version.dwMinorVersion >= version_data[idx].info.minor))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (idx < 0) return TRUE;
|
||||||
|
ver = &windows8_version_info;
|
||||||
|
|
||||||
|
if (RtlQueryInformationActivationContext(0, NtCurrentTeb()->Peb->ActivationContextData, NULL,
|
||||||
|
CompatibilityInformationInActivationContext, NULL, 0, &req) != STATUS_BUFFER_TOO_SMALL
|
||||||
|
|| !req)
|
||||||
|
goto done;
|
||||||
|
|
||||||
|
if (!(acci = HeapAlloc(GetProcessHeap(), 0, req)))
|
||||||
|
{
|
||||||
|
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (RtlQueryInformationActivationContext(0, NtCurrentTeb()->Peb->ActivationContextData, NULL,
|
||||||
|
CompatibilityInformationInActivationContext, acci, req, &req) == STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
COMPATIBILITY_CONTEXT_ELEMENT *elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1);
|
||||||
|
DWORD i, count = *acci;
|
||||||
|
|
||||||
|
for (i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
if (elements[i].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS &&
|
||||||
|
IsEqualGUID(&elements[i].Id, &version_data[idx].guid))
|
||||||
|
{
|
||||||
|
ver = &version_data[idx].info;
|
||||||
|
|
||||||
|
if (ver->major == current_version.dwMajorVersion &&
|
||||||
|
ver->minor == current_version.dwMinorVersion)
|
||||||
|
ver = NULL;
|
||||||
|
|
||||||
|
idx = 0; /* break from outer loop */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (idx--);
|
||||||
|
}
|
||||||
|
HeapFree(GetProcessHeap(), 0, acci);
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ver)
|
||||||
|
{
|
||||||
|
current_version.dwMajorVersion = ver->major;
|
||||||
|
current_version.dwMinorVersion = ver->minor;
|
||||||
|
current_version.dwBuildNumber = ver->build;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* find_entry_by_id
|
* find_entry_by_id
|
||||||
*
|
*
|
||||||
|
@ -1317,7 +1434,7 @@ DWORD WINAPI GetVersion(void)
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info )
|
BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info )
|
||||||
{
|
{
|
||||||
RTL_OSVERSIONINFOEXW infoW;
|
OSVERSIONINFOEXW infoW;
|
||||||
|
|
||||||
if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) &&
|
if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOA) &&
|
||||||
info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA))
|
info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXA))
|
||||||
|
@ -1328,7 +1445,7 @@ BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info )
|
||||||
}
|
}
|
||||||
|
|
||||||
infoW.dwOSVersionInfoSize = sizeof(infoW);
|
infoW.dwOSVersionInfoSize = sizeof(infoW);
|
||||||
if (!set_ntstatus( RtlGetVersion( &infoW ))) return FALSE;
|
if (!GetVersionExW( (OSVERSIONINFOW *)&infoW )) return FALSE;
|
||||||
|
|
||||||
info->dwMajorVersion = infoW.dwMajorVersion;
|
info->dwMajorVersion = infoW.dwMajorVersion;
|
||||||
info->dwMinorVersion = infoW.dwMinorVersion;
|
info->dwMinorVersion = infoW.dwMinorVersion;
|
||||||
|
@ -1354,11 +1471,30 @@ BOOL WINAPI GetVersionExA( OSVERSIONINFOA *info )
|
||||||
*/
|
*/
|
||||||
BOOL WINAPI GetVersionExW( OSVERSIONINFOW *info )
|
BOOL WINAPI GetVersionExW( OSVERSIONINFOW *info )
|
||||||
{
|
{
|
||||||
|
static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT;
|
||||||
|
|
||||||
if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) &&
|
if (info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOW) &&
|
||||||
info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW))
|
info->dwOSVersionInfoSize != sizeof(OSVERSIONINFOEXW))
|
||||||
{
|
{
|
||||||
WARN( "wrong OSVERSIONINFO size from app (got: %d)\n", info->dwOSVersionInfoSize );
|
WARN( "wrong OSVERSIONINFO size from app (got: %d)\n", info->dwOSVersionInfoSize );
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
return set_ntstatus( RtlGetVersion( (RTL_OSVERSIONINFOEXW *)info ));
|
|
||||||
|
if (!InitOnceExecuteOnce(&init_once, init_current_version, NULL, NULL)) return FALSE;
|
||||||
|
|
||||||
|
info->dwMajorVersion = current_version.dwMajorVersion;
|
||||||
|
info->dwMinorVersion = current_version.dwMinorVersion;
|
||||||
|
info->dwBuildNumber = current_version.dwBuildNumber;
|
||||||
|
info->dwPlatformId = current_version.dwPlatformId;
|
||||||
|
wcscpy( info->szCSDVersion, current_version.szCSDVersion );
|
||||||
|
|
||||||
|
if (info->dwOSVersionInfoSize == sizeof(OSVERSIONINFOEXW))
|
||||||
|
{
|
||||||
|
OSVERSIONINFOEXW *vex = (OSVERSIONINFOEXW *)info;
|
||||||
|
vex->wServicePackMajor = current_version.wServicePackMajor;
|
||||||
|
vex->wServicePackMinor = current_version.wServicePackMinor;
|
||||||
|
vex->wSuiteMask = current_version.wSuiteMask;
|
||||||
|
vex->wProductType = current_version.wProductType;
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue