From 2d519f5aa451513a6e12dec7855c08cd1b8d12fb Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Mon, 19 Apr 2021 13:33:21 +0200 Subject: [PATCH] ntdll: Support MaxVersionTested in the manifest compatibility element. Signed-off-by: Alexandre Julliard --- dlls/kernel32/tests/actctx.c | 83 +++++++++++++++++++++++++++++------- dlls/ntdll/actctx.c | 50 +++++++++++++++++++--- include/winnt.h | 1 + 3 files changed, 112 insertions(+), 22 deletions(-) diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index 4a6a22680e2..f7830d36b7b 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -429,6 +429,8 @@ static const char compat_manifest_vista_7_8_10_81[] = " " /* Windows 8 */ " " /* Windows 10 */ " " /* Windows 8.1 */ +" " +" " " " " " ""; @@ -2818,6 +2820,20 @@ typedef struct _test_act_ctx_compat_info { COMPATIBILITY_CONTEXT_ELEMENT Elements[10]; } test_act_ctx_compat_info; +/* Win10 versions before 1909 don't have the MaxVersionTested field */ +typedef struct +{ + GUID Id; + ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type; +} old_win10_COMPATIBILITY_CONTEXT_ELEMENT; + +typedef struct +{ + DWORD ElementCount; + old_win10_COMPATIBILITY_CONTEXT_ELEMENT Elements[10]; +} old_win10_test_act_ctx_compat_info; + + static void test_no_compat(HANDLE handle, int line) { test_act_ctx_compat_info compat_info; @@ -2829,15 +2845,17 @@ static void test_no_compat(HANDLE handle, int line) &compat_info, sizeof(compat_info), &size); ok_(__FILE__, line)(b, "CompatibilityInformationInActivationContext failed\n"); - ok_(__FILE__, line)(size == sizeof(DWORD), "size mismatch (got %lu, expected 4)\n", size); + ok_(__FILE__, line)(size == offsetof(test_act_ctx_compat_info,Elements[0]) || + broken(size == offsetof(old_win10_test_act_ctx_compat_info,Elements[0])), + "size mismatch got %lu\n", size); ok_(__FILE__, line)(compat_info.ElementCount == 0, "unexpected ElementCount %u\n", compat_info.ElementCount); } -static void test_with_compat(HANDLE handle, DWORD num_compat, const GUID* expected_compat[], int line) +static void test_with_compat(HANDLE handle, DWORD num_compat, DWORD num_version, + const GUID *expected_compat[], const ULONGLONG expected_version[], int line) { test_act_ctx_compat_info compat_info; SIZE_T size; - SIZE_T expected = sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * num_compat + sizeof(DWORD); DWORD n; BOOL b; @@ -2846,18 +2864,46 @@ static void test_with_compat(HANDLE handle, DWORD num_compat, const GUID* expect &compat_info, sizeof(compat_info), &size); ok_(__FILE__, line)(b, "CompatibilityInformationInActivationContext failed\n"); - ok_(__FILE__, line)(size == expected, "size mismatch (got %lu, expected %lu)\n", size, expected); - ok_(__FILE__, line)(compat_info.ElementCount == num_compat, "unexpected ElementCount %u\n", compat_info.ElementCount); + ok_(__FILE__, line)(size == offsetof(test_act_ctx_compat_info,Elements[num_compat + num_version]) || + broken(size == offsetof(old_win10_test_act_ctx_compat_info,Elements[num_compat])), + "size mismatch got %lu\n", size); + ok_(__FILE__, line)(compat_info.ElementCount == num_compat + num_version || + broken(compat_info.ElementCount == num_compat), + "unexpected ElementCount %u\n", compat_info.ElementCount); - for (n = 0; n < num_compat; ++n) + if (size == offsetof(old_win10_test_act_ctx_compat_info,Elements[num_compat])) { - ok_(__FILE__, line)(IsEqualGUID(&compat_info.Elements[n].Id, expected_compat[n]), - "got wrong clsid %s, expected %s for %u\n", - wine_dbgstr_guid(&compat_info.Elements[n].Id), - wine_dbgstr_guid(expected_compat[n]), - n); - ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, - "Wrong type, got %u for %u\n", (DWORD)compat_info.Elements[n].Type, n); + for (n = 0; n < num_compat; ++n) + { + old_win10_test_act_ctx_compat_info *info = (old_win10_test_act_ctx_compat_info *)&compat_info; + ok_(__FILE__, line)(IsEqualGUID(&info->Elements[n].Id, expected_compat[n]), + "got wrong clsid %s, expected %s for %u\n", + wine_dbgstr_guid(&info->Elements[n].Id), + wine_dbgstr_guid(expected_compat[n]), + n); + ok_(__FILE__, line)(info->Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, + "Wrong type, got %u for %u\n", (DWORD)info->Elements[n].Type, n); + } + } + else + { + for (n = 0; n < num_compat; ++n) + { + ok_(__FILE__, line)(IsEqualGUID(&compat_info.Elements[n].Id, expected_compat[n]), + "got wrong clsid %s, expected %s for %u\n", + wine_dbgstr_guid(&compat_info.Elements[n].Id), + wine_dbgstr_guid(expected_compat[n]), + n); + ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_OS, + "Wrong type, got %u for %u\n", (DWORD)compat_info.Elements[n].Type, n); + } + for (; n < num_compat + num_version; ++n) + { + ok_(__FILE__, line)(compat_info.Elements[n].Type == ACTCTX_COMPATIBILITY_ELEMENT_TYPE_MAXVERSIONTESTED, + "Wrong type, got %u for %u\n", (DWORD)compat_info.Elements[n].Type, n); + ok_(__FILE__, line)(compat_info.Elements[n].MaxVersionTested == expected_version[n - num_compat], + "Wrong version, got %s for %u\n", wine_dbgstr_longlong(compat_info.Elements[n].MaxVersionTested), n); + } } } @@ -2931,7 +2977,7 @@ static void test_compatibility(void) &VISTA_COMPAT_GUID }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 1, expect_manifest, __LINE__); + test_with_compat(handle, 1, 0, expect_manifest, NULL, __LINE__); ReleaseActCtx(handle); } @@ -2955,8 +3001,13 @@ static void test_compatibility(void) &WIN10_COMPAT_GUID, &WIN81_COMPAT_GUID, }; + static const ULONGLONG expect_version[] = + { + 0x000a000047b60000ull, /* 10.0.18358.0 */ + 0x0002000300040005ull, /* 2.3.4.5 */ + }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 5, expect_manifest, __LINE__); + test_with_compat(handle, 5, 2, expect_manifest, expect_version, __LINE__); ReleaseActCtx(handle); } @@ -2977,7 +3028,7 @@ static void test_compatibility(void) &OTHER_COMPAT_GUID, }; test_basic_info(handle, __LINE__); - test_with_compat(handle, 1, expect_manifest, __LINE__); + test_with_compat(handle, 1, 0, expect_manifest, NULL, __LINE__); ReleaseActCtx(handle); } } diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 5032f1b0cc4..9a85085dd6a 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -2327,6 +2327,38 @@ static void parse_supportedos_elem( xmlbuf_t *xmlbuf, struct assembly *assembly, if (!end) parse_expect_end_elem(xmlbuf, parent); } +static void parse_maxversiontested_elem( xmlbuf_t *xmlbuf, struct assembly *assembly, + struct actctx_loader *acl, const struct xml_elem *parent ) +{ + struct xml_attr attr; + BOOL end = FALSE; + + while (next_xml_attr(xmlbuf, &attr, &end)) + { + if (xml_attr_cmp(&attr, L"Id")) + { + COMPATIBILITY_CONTEXT_ELEMENT *compat; + struct assembly_version version; + + if (!(compat = add_compat_context(assembly))) + { + set_error( xmlbuf ); + return; + } + parse_version( &attr.value, &version ); + compat->Type = ACTCTX_COMPATIBILITY_ELEMENT_TYPE_MAXVERSIONTESTED; + compat->MaxVersionTested = (ULONGLONG)version.major << 48 | + (ULONGLONG)version.minor << 32 | version.build << 16 | version.revision; + } + else if (!is_xmlns_attr( &attr )) + { + WARN("unknown attr %s\n", debugstr_xml_attr(&attr)); + } + } + + if (!end) parse_expect_end_elem(xmlbuf, parent); +} + static void parse_compatibility_application_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader* acl, const struct xml_elem *parent) { @@ -2338,6 +2370,10 @@ static void parse_compatibility_application_elem(xmlbuf_t *xmlbuf, struct assemb { parse_supportedos_elem(xmlbuf, assembly, acl, &elem); } + else if (xml_elem_cmp(&elem, L"maxversiontested", compatibilityNSW)) + { + parse_maxversiontested_elem(xmlbuf, assembly, acl, &elem); + } else { WARN("unknown elem %s\n", debugstr_xml_elem(&elem)); @@ -5328,8 +5364,11 @@ NTSTATUS WINAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle case CompatibilityInformationInActivationContext: { - /*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci = buffer; - COMPATIBILITY_CONTEXT_ELEMENT *elements; + struct acci + { + DWORD ElementCount; + COMPATIBILITY_CONTEXT_ELEMENT Elements[1]; + } *acci = buffer; struct assembly *assembly = NULL; ULONG num_compat_contexts = 0, n; SIZE_T len; @@ -5340,16 +5379,15 @@ NTSTATUS WINAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle if (assembly) num_compat_contexts = assembly->num_compat_contexts; - len = sizeof(*acci) + num_compat_contexts * sizeof(COMPATIBILITY_CONTEXT_ELEMENT); + len = offsetof( struct acci, Elements[num_compat_contexts] ); if (retlen) *retlen = len; if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL; - *acci = num_compat_contexts; - elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1); + acci->ElementCount = num_compat_contexts; for (n = 0; n < num_compat_contexts; ++n) { - elements[n] = assembly->compat_contexts[n]; + acci->Elements[n] = assembly->compat_contexts[n]; } } break; diff --git a/include/winnt.h b/include/winnt.h index 840966f657b..0843ee3f739 100644 --- a/include/winnt.h +++ b/include/winnt.h @@ -6442,6 +6442,7 @@ typedef enum { typedef struct _COMPATIBILITY_CONTEXT_ELEMENT { GUID Id; ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type; + ULONGLONG MaxVersionTested; } COMPATIBILITY_CONTEXT_ELEMENT, *PCOMPATIBILITY_CONTEXT_ELEMENT; #if !defined(__WINESRC__) && (defined(_MSC_EXTENSIONS) || ((defined(__GNUC__) && __GNUC__ >= 3)))