[PATCH v2 1/3] kernelbase: Implement compatibility mode for GetVersionEx.

Gabriel Ivăncescu gabrielopcode at gmail.com
Wed Mar 18 08:09:40 CDT 2020


On 17/03/2020 19:24, Nikolay Sivov wrote:
> 
> 
> On 3/17/20 7:50 PM, Gabriel Ivăncescu wrote:
>> On 17/03/2020 18:28, Nikolay Sivov wrote:
>>> On 3/17/20 7:07 PM, Gabriel Ivăncescu wrote:
>>>> +/*********************************************************************** 
>>>>
>>>> + * Win8 info, reported if app doesn't provide compat GUID in manifest.
>>>> + */
>>>> +static const RTL_OSVERSIONINFOEXW windows8_version_data =
>>>> +{
>>>> +    sizeof(RTL_OSVERSIONINFOEXW), 6, 2, 0x23f0, VER_PLATFORM_WIN32_NT,
>>>> +    {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
>>>> +};
>>>> +
>>>> +
>>>> +/*********************************************************************** 
>>>>
>>>> + * Windows versions that need compatibility GUID specified in manifest
>>>> + * in order to be reported by the APIs.
>>>> + */
>>>> +static const struct
>>>> +{
>>>> +    RTL_OSVERSIONINFOEXW info;
>>>> +    GUID guid;
>>>> +} version_data[] =
>>>> +{
>>>> +    /* Windows 8.1 */
>>>> +    {
>>>> +        {
>>>> +            sizeof(RTL_OSVERSIONINFOEXW), 6, 3, 0x2580, 
>>>> VER_PLATFORM_WIN32_NT,
>>>> +            {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
>>>> +        },
>>>> + {0x1f676c76,0x80e1,0x4239,{0x95,0xbb,0x83,0xd0,0xf6,0xd0,0xda,0x78}}
>>>> +    },
>>>> +    /* Windows 10 */
>>>> +    {
>>>> +        {
>>>> +            sizeof(RTL_OSVERSIONINFOEXW), 10, 0, 0x42ee, 
>>>> VER_PLATFORM_WIN32_NT,
>>>> +            {0}, 0, 0, VER_SUITE_SINGLEUSERTS, VER_NT_WORKSTATION, 0
>>>> +        },
>>>> + {0x8e0f7a12,0xbfb3,0x4fe8,{0xb9,0xa5,0x48,0xfd,0x50,0xa1,0x5a,0x9a}}
>>>> +    }
>>>> +};
>>> For that you only need to store 3 values - major/minor/build.
>>
>> Ah alright, I just copy-pasted the entires from ntdll.
>>
>>>> +/*********************************************************************** 
>>>>
>>>> + * Holds the current version (including compatibility mode).
>>>> + * Call init_current_version before using it.
>>>> + */
>>>> +static RTL_OSVERSIONINFOEXW current_version;
>>>> +
>>>> +
>>>> +/****************************************************************************** 
>>>>
>>>> + *  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 BOOL CALLBACK init_current_version_callback(PINIT_ONCE 
>>>> init_once, PVOID parameter, PVOID *context)
>>>> +{
>>> Should it actually be static and initialized once? What happens if 
>>> you activate another context dynamically?
>>>
>>
>> I actually have no idea, didn't know you can do that. I'm somewhat 
>> unfamiliar with activation context APIs. What API should I be using to 
>> test this?
> 
> There are functions to create, activate and deactivate contexts. We use 
> that in tests for example.
> 

So, I tested with the ACTCTX_FLAG_SET_PROCESS_DEFAULT flag for 
CreateActCtx, followed by ActivateActCtx, at the beginning of the test.

Just to make sure, I retrieved the GUIDs with 
CompatibilityInformationInActivationContext and they seemed in order, so 
the manifest was loaded correctly and the activation context pushed. 
i.e. it returned the same GUIDs as if the app itself had the manifest, 
without pushing it manually on the stack.

However, GetVersionEx reported Windows 8, as if no manifest. So I 
suspect it gets cached at startup somewhere... and any further 
activation context changes won't matter.

Any idea of a good place to do that? It must be a point where the 
default activation context become available but application code hasn't 
run yet. Would DllMain for kernelbase be a good place to cache it?

Thanks,
Gabriel



More information about the wine-devel mailing list