diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c
index af3dadf79a5..2cb856abb43 100644
--- a/dlls/kernel32/tests/actctx.c
+++ b/dlls/kernel32/tests/actctx.c
@@ -315,6 +315,57 @@ static const char wrong_depmanifest1[] =
""
"";
+static const char compat_manifest_no_supportedOs[] =
+""
+" "
+" "
+" "
+" "
+" "
+"";
+
+static const char compat_manifest_vista[] =
+""
+" "
+" "
+" "
+" " /* Windows Vista */
+" "
+" "
+"";
+
+static const char compat_manifest_vista_7_8_10_81[] =
+""
+" "
+" "
+" "
+" " /* Windows Vista */
+" " /* Windows 7 */
+" " /* Windows 8 */
+" " /* Windows 10 */
+" " /* Windows 8.1 */
+" "
+" "
+"";
+
+static const char compat_manifest_other_guid[] =
+""
+" "
+" "
+" "
+" "
+" "
+" "
+"";
+
+DEFINE_GUID(VISTA_COMPAT_GUID, 0xe2011457, 0x1546, 0x43c5, 0xa5, 0xfe, 0x00, 0x8d, 0xee, 0xe3, 0xd3, 0xf0);
+DEFINE_GUID(WIN7_COMPAT_GUID, 0x35138b9a, 0x5d96, 0x4fbd, 0x8e, 0x2d, 0xa2, 0x44, 0x02, 0x25, 0xf9, 0x3a);
+DEFINE_GUID(WIN8_COMPAT_GUID, 0x4a2f28e3, 0x53b9, 0x4441, 0xba, 0x9c, 0xd6, 0x9d, 0x4a, 0x4a, 0x6e, 0x38);
+DEFINE_GUID(WIN81_COMPAT_GUID, 0x1f676c76, 0x80e1, 0x4239, 0x95, 0xbb, 0x83, 0xd0, 0xf6, 0xd0, 0xda, 0x78);
+DEFINE_GUID(WIN10_COMPAT_GUID, 0x8e0f7a12, 0xbfb3, 0x4fe8, 0xb9, 0xa5, 0x48, 0xfd, 0x50, 0xa1, 0x5a, 0x9a);
+DEFINE_GUID(OTHER_COMPAT_GUID, 0x12345566, 0x1111, 0x2222, 0x33, 0x33, 0x44, 0x44, 0x44, 0x44, 0x44, 0x44);
+
+
static const WCHAR testlib_dll[] =
{'t','e','s','t','l','i','b','.','d','l','l',0};
static const WCHAR testlib2_dll[] =
@@ -2487,6 +2538,183 @@ todo_wine
pReleaseActCtx(handle);
}
+/* Test structure to verify alignment */
+typedef struct _test_act_ctx_compat_info {
+ DWORD ElementCount;
+ COMPATIBILITY_CONTEXT_ELEMENT Elements[10];
+} test_act_ctx_compat_info;
+
+static void test_no_compat(HANDLE handle, int line)
+{
+ test_act_ctx_compat_info compat_info;
+ SIZE_T size;
+ BOOL b;
+
+ memset(&compat_info, 0, sizeof(compat_info));
+ b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL,
+ CompatibilityInformationInActivationContext, &compat_info,
+ sizeof(compat_info), &size);
+
+todo_wine {
+ ok_(__FILE__, line)(b, "CompatibilityInformationInActivationContext failed\n");
+ ok_(__FILE__, line)(size == sizeof(DWORD), "size mismatch (got %lu, expected 4)\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)
+{
+ 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;
+
+ memset(&compat_info, 0, sizeof(compat_info));
+ b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL,
+ CompatibilityInformationInActivationContext, &compat_info,
+ sizeof(compat_info), &size);
+
+todo_wine {
+ 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);
+
+ 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 == ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS,
+ "Wrong type, got %u for %u\n", (DWORD)compat_info.Elements[n].Type, n);
+ }
+}
+}
+
+static void test_compatibility(void)
+{
+ HANDLE handle;
+
+ /* No compat results returned */
+ trace("manifest1\n");
+ if(!create_manifest_file("test1.manifest", manifest1, -1, NULL, NULL))
+ {
+ skip("Could not create manifest file\n");
+ return;
+ }
+ handle = test_create("test1.manifest");
+ ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+ DeleteFileA("test1.manifest");
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ char buffer[sizeof(COMPATIBILITY_CONTEXT_ELEMENT) * 2 + sizeof(DWORD)];
+ SIZE_T size;
+ BOOL b;
+
+ memset(buffer, 0, sizeof(buffer));
+ b = pQueryActCtxW(QUERY_ACTCTX_FLAG_NO_ADDREF, handle, NULL,
+ CompatibilityInformationInActivationContext, buffer,
+ sizeof(buffer), &size);
+
+ if (!b && GetLastError() == ERROR_INVALID_PARAMETER)
+ {
+ win_skip("CompatibilityInformationInActivationContext not supported.\n");
+ pReleaseActCtx(handle);
+ return;
+ }
+
+ test_basic_info(handle, __LINE__);
+ test_no_compat(handle, __LINE__);
+ pReleaseActCtx(handle);
+ }
+
+ /* Still no compat results returned */
+ trace("no_supportedOs\n");
+ if(!create_manifest_file("no_supportedOs.manifest", compat_manifest_no_supportedOs, -1, NULL, NULL))
+ {
+ skip("Could not create manifest file\n");
+ return;
+ }
+ handle = test_create("no_supportedOs.manifest");
+ ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+ DeleteFileA("no_supportedOs.manifest");
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ test_basic_info(handle, __LINE__);
+ test_no_compat(handle, __LINE__);
+ pReleaseActCtx(handle);
+ }
+
+ /* Just one result returned */
+ trace("manifest_vista\n");
+ if(!create_manifest_file("manifest_vista.manifest", compat_manifest_vista, -1, NULL, NULL))
+ {
+ skip("Could not create manifest file\n");
+ return;
+ }
+ handle = test_create("manifest_vista.manifest");
+ ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+ DeleteFileA("manifest_vista.manifest");
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ static const GUID* expect_manifest[] =
+ {
+ &VISTA_COMPAT_GUID
+ };
+ test_basic_info(handle, __LINE__);
+ test_with_compat(handle, 1, expect_manifest, __LINE__);
+ pReleaseActCtx(handle);
+ }
+
+ /* Show that the order is retained */
+ trace("manifest_vista_7_8_10_81\n");
+ if(!create_manifest_file("manifest_vista_7_8_10_81.manifest", compat_manifest_vista_7_8_10_81, -1, NULL, NULL))
+ {
+ skip("Could not create manifest file\n");
+ return;
+ }
+ handle = test_create("manifest_vista_7_8_10_81.manifest");
+ ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+ DeleteFileA("manifest_vista_7_8_10_81.manifest");
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ static const GUID* expect_manifest[] =
+ {
+ &VISTA_COMPAT_GUID,
+ &WIN7_COMPAT_GUID,
+ &WIN8_COMPAT_GUID,
+ &WIN10_COMPAT_GUID,
+ &WIN81_COMPAT_GUID,
+ };
+ test_basic_info(handle, __LINE__);
+ test_with_compat(handle, 5, expect_manifest, __LINE__);
+ pReleaseActCtx(handle);
+ }
+
+ /* Show that even unknown GUID's are stored */
+ trace("manifest_other_guid\n");
+ if(!create_manifest_file("manifest_other_guid.manifest", compat_manifest_other_guid, -1, NULL, NULL))
+ {
+ skip("Could not create manifest file\n");
+ return;
+ }
+ handle = test_create("manifest_other_guid.manifest");
+ ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+ DeleteFileA("manifest_other_guid.manifest");
+ if(handle != INVALID_HANDLE_VALUE)
+ {
+ static const GUID* expect_manifest[] =
+ {
+ &OTHER_COMPAT_GUID,
+ };
+ test_basic_info(handle, __LINE__);
+ test_with_compat(handle, 1, expect_manifest, __LINE__);
+ pReleaseActCtx(handle);
+ }
+}
+
START_TEST(actctx)
{
int argc;
@@ -2511,4 +2739,5 @@ START_TEST(actctx)
test_findsectionstring();
test_ZombifyActCtx();
run_child_process();
+ test_compatibility();
}