[RTL][XDK][KERNERL32_WINETEST] Import wine actctx changes from 3.2-37c98396
authorMark Jansen <mark.jansen@reactos.org>
Mon, 19 Feb 2018 21:23:39 +0000 (22:23 +0100)
committerMark Jansen <mark.jansen@reactos.org>
Mon, 19 Feb 2018 21:23:39 +0000 (22:23 +0100)
This adds support for reading the trustInfo (requestedExecutionLevel),
and the compatibility (supportedOs) sections.

dll/win32/kernel32/client/actctx.c
modules/rostests/winetests/kernel32/actctx.c
sdk/include/xdk/winnt_old.h
sdk/lib/rtl/actctx.c

index f268e27..302d6c8 100644 (file)
@@ -374,6 +374,8 @@ QueryActCtxW(IN DWORD dwFlags,
     {
         case ActivationContextBasicInformation:
         case ActivationContextDetailedInformation:
+        case CompatibilityInformationInActivationContext:
+        case RunlevelInformationInActivationContext:
 
             /* Nothing to check */
             break;
index 5a41c40..8bd37c4 100644 (file)
@@ -395,6 +395,57 @@ static const char wrong_depmanifest1[] =
 "<assemblyIdentity type=\"win32\" name=\"testdep\" version=\"6.5.4.4\" processorArchitecture=\"" ARCH "\" />"
 "</assembly>";
 
+static const char compat_manifest_no_supportedOs[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"   <assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"   <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">"
+"       <application>"
+"       </application>"
+"   </compatibility>"
+"</assembly>";
+
+static const char compat_manifest_vista[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"   <assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"   <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">"
+"       <application>"
+"           <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" />"  /* Windows Vista */
+"       </application>"
+"   </compatibility>"
+"</assembly>";
+
+static const char compat_manifest_vista_7_8_10_81[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"   <assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"   <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">"
+"       <application>"
+"           <supportedOS Id=\"{e2011457-1546-43c5-a5fe-008deee3d3f0}\" />"  /* Windows Vista */
+"           <supportedOS Id=\"{35138b9a-5d96-4fbd-8e2d-a2440225f93a}\" />"  /* Windows 7 */
+"           <supportedOS Id=\"{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}\" />"  /* Windows 8 */
+"           <supportedOS Id=\"{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}\" />"  /* Windows 10 */
+"           <supportedOS Id=\"{1f676c76-80e1-4239-95bb-83d0f6d0da78}\" />"  /* Windows 8.1 */
+"       </application>"
+"   </compatibility>"
+"</assembly>";
+
+static const char compat_manifest_other_guid[] =
+"<assembly xmlns=\"urn:schemas-microsoft-com:asm.v1\" manifestVersion=\"1.0\">"
+"   <assemblyIdentity version=\"1.0.0.0\"  name=\"Wine.Test\" type=\"win32\"></assemblyIdentity>"
+"   <compatibility xmlns=\"urn:schemas-microsoft-com:compatibility.v1\">"
+"       <application>"
+"           <supportedOS Id=\"{12345566-1111-2222-3333-444444444444}\" />"
+"       </application>"
+"   </compatibility>"
+"</assembly>";
+
+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[] =
@@ -894,7 +945,7 @@ static HANDLE test_create(const char *file)
     return handle;
 }
 
-static void test_create_and_fail(const char *manifest, const char *depmanifest, int todo)
+static void test_create_and_fail(const char *manifest, const char *depmanifest, int todo, BOOL is_broken)
 {
     ACTCTXW actctx;
     HANDLE handle;
@@ -909,8 +960,14 @@ static void test_create_and_fail(const char *manifest, const char *depmanifest,
     handle = pCreateActCtxW(&actctx);
     todo_wine_if(todo)
     {
-        ok(handle == INVALID_HANDLE_VALUE, "handle != INVALID_HANDLE_VALUE\n");
-        ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "GetLastError == %u\n", GetLastError());
+        if (is_broken)
+            ok(broken(handle != INVALID_HANDLE_VALUE) || handle == INVALID_HANDLE_VALUE,
+                "Unexpected context handle %p.\n", handle);
+        else
+            ok(handle == INVALID_HANDLE_VALUE, "Unexpected context handle %p.\n", handle);
+
+        if (handle == INVALID_HANDLE_VALUE)
+            ok(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX, "Unexpected error %d.\n", GetLastError());
     }
     if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx( handle );
     DeleteFileA("bad.manifest");
@@ -953,31 +1010,31 @@ static void test_create_fail(void)
     ok(GetLastError() == ERROR_FILE_NOT_FOUND, "GetLastError == %u\n", GetLastError());
 
     trace("wrong_manifest1\n");
-    test_create_and_fail(wrong_manifest1, NULL, 0 );
+    test_create_and_fail(wrong_manifest1, NULL, 0, FALSE);
     trace("wrong_manifest2\n");
-    test_create_and_fail(wrong_manifest2, NULL, 0 );
+    test_create_and_fail(wrong_manifest2, NULL, 0, FALSE);
     trace("wrong_manifest3\n");
-    test_create_and_fail(wrong_manifest3, NULL, 1 );
+    test_create_and_fail(wrong_manifest3, NULL, 1, FALSE);
     trace("wrong_manifest4\n");
-    test_create_and_fail(wrong_manifest4, NULL, 1 );
+    test_create_and_fail(wrong_manifest4, NULL, 1, FALSE);
     trace("wrong_manifest5\n");
-    test_create_and_fail(wrong_manifest5, NULL, 0 );
+    test_create_and_fail(wrong_manifest5, NULL, 0, FALSE);
     trace("wrong_manifest6\n");
-    test_create_and_fail(wrong_manifest6, NULL, 0 );
+    test_create_and_fail(wrong_manifest6, NULL, 0, FALSE);
     trace("wrong_manifest7\n");
-    test_create_and_fail(wrong_manifest7, NULL, 1 );
+    test_create_and_fail(wrong_manifest7, NULL, 1, FALSE);
     trace("wrong_manifest8\n");
-    test_create_and_fail(wrong_manifest8, NULL, 0 );
+    test_create_and_fail(wrong_manifest8, NULL, 0, FALSE);
     trace("wrong_manifest9\n");
-    test_create_and_fail(wrong_manifest9, NULL, 0 );
+    test_create_and_fail(wrong_manifest9, NULL, 0, TRUE /* WinXP */);
     trace("wrong_manifest10\n");
-    test_create_and_fail(wrong_manifest10, NULL, 0 );
+    test_create_and_fail(wrong_manifest10, NULL, 0, TRUE /* WinXP */);
     trace("UTF-16 manifest1 without BOM\n");
     test_create_wide_and_fail(manifest1, FALSE );
     trace("manifest2\n");
-    test_create_and_fail(manifest2, NULL, 0 );
+    test_create_and_fail(manifest2, NULL, 0, FALSE);
     trace("manifest2+depmanifest1\n");
-    test_create_and_fail(manifest2, wrong_depmanifest1, 0 );
+    test_create_and_fail(manifest2, wrong_depmanifest1, 0, FALSE);
 }
 
 struct strsection_header
@@ -1909,8 +1966,6 @@ static void test_actctx(void)
     HANDLE handle;
     BOOL b;
 
-    test_create_fail();
-
     trace("default actctx\n");
 
     b = pGetCurrentActCtx(&handle);
@@ -2095,7 +2150,8 @@ static void test_actctx(void)
 
     if(create_manifest_file("test6.manifest", manifest6, -1, NULL, NULL)) {
         handle = test_create("test6.manifest");
-        ok(handle != INVALID_HANDLE_VALUE, "handle == INVALID_HANDLE_VALUE, error %u\n", GetLastError());
+        ok(handle != INVALID_HANDLE_VALUE || broken(handle == INVALID_HANDLE_VALUE) /* WinXP */,
+            "Unexpected context handle %p.\n", handle);
         DeleteFileA("test6.manifest");
         DeleteFileA("testdep.manifest");
         if(handle != INVALID_HANDLE_VALUE)
@@ -2267,7 +2323,7 @@ static HANDLE create_manifest(const char *filename, const char *data, int line)
     return handle;
 }
 
-static void kernel32_find(ULONG section, const char *string_to_find, BOOL should_find, int line)
+static void kernel32_find(ULONG section, const char *string_to_find, BOOL should_find, BOOL todo, int line)
 {
     UNICODE_STRING string_to_findW;
     ACTCTX_SECTION_KEYED_DATA data;
@@ -2284,6 +2340,7 @@ static void kernel32_find(ULONG section, const char *string_to_find, BOOL should
     err = GetLastError();
     ok_(__FILE__, line)(ret == should_find,
         "FindActCtxSectionStringA: expected ret = %u, got %u\n", should_find, ret);
+    todo_wine_if(todo)
     ok_(__FILE__, line)(err == (should_find ? ERROR_SUCCESS : ERROR_SXS_KEY_NOT_FOUND),
         "FindActCtxSectionStringA: unexpected error %u\n", err);
 
@@ -2295,6 +2352,7 @@ static void kernel32_find(ULONG section, const char *string_to_find, BOOL should
     err = GetLastError();
     ok_(__FILE__, line)(ret == should_find,
         "FindActCtxSectionStringW: expected ret = %u, got %u\n", should_find, ret);
+    todo_wine_if(todo)
     ok_(__FILE__, line)(err == (should_find ? ERROR_SUCCESS : ERROR_SXS_KEY_NOT_FOUND),
         "FindActCtxSectionStringW: unexpected error %u\n", err);
 
@@ -2317,7 +2375,7 @@ static void kernel32_find(ULONG section, const char *string_to_find, BOOL should
     pRtlFreeUnicodeString(&string_to_findW);
 }
 
-static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_find, int line)
+static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_find, BOOL todo, int line)
 {
     UNICODE_STRING string_to_findW;
     ACTCTX_SECTION_KEYED_DATA data;
@@ -2329,10 +2387,12 @@ static void ntdll_find(ULONG section, const char *string_to_find, BOOL should_fi
     data.cbSize = sizeof(data);
 
     ret = pRtlFindActivationContextSectionString(0, NULL, section, &string_to_findW, &data);
+    todo_wine_if(todo)
     ok_(__FILE__, line)(ret == (should_find ? STATUS_SUCCESS : STATUS_SXS_KEY_NOT_FOUND),
         "RtlFindActivationContextSectionString: unexpected status 0x%x\n", ret);
 
     ret = pRtlFindActivationContextSectionString(0, NULL, section, &string_to_findW, NULL);
+    todo_wine_if(todo)
     ok_(__FILE__, line)(ret == (should_find ? STATUS_SUCCESS : STATUS_SXS_KEY_NOT_FOUND),
         "RtlFindActivationContextSectionString: unexpected status 0x%x\n", ret);
 
@@ -2350,22 +2410,22 @@ static void test_findsectionstring(void)
     ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
 
     /* first we show the parameter validation from kernel32 */
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, __LINE__);
-    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, TRUE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, FALSE, __LINE__);
+    kernel32_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, FALSE, __LINE__);
 
     /* then we show that ntdll plays by different rules */
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, __LINE__);
-    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION, "testdep", FALSE, TRUE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib.dll", TRUE, FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib2.dll", TRUE, FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION, "testlib3.dll", FALSE, FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass", TRUE, FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass2", TRUE, FALSE, __LINE__);
+    ntdll_find(ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION, "wndClass3", FALSE, FALSE, __LINE__);
 
     ret = pDeactivateActCtx(0, cookie);
     ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
@@ -2683,6 +2743,179 @@ 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);
+
+    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);
+
+    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;
@@ -2703,8 +2936,10 @@ START_TEST(actctx)
     }
 
     test_actctx();
+    test_create_fail();
     test_CreateActCtx();
     test_findsectionstring();
     test_ZombifyActCtx();
     run_child_process();
+    test_compatibility();
 }
index 415f332..f03582a 100644 (file)
@@ -3908,6 +3908,22 @@ typedef struct _ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION {
   DWORD UiAccess;
 } ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION, *PACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION;
 
+typedef enum {
+  ACTCX_COMPATIBILITY_ELEMENT_TYPE_UNKNOWN = 0,
+  ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS
+} ACTCTX_COMPATIBILITY_ELEMENT_TYPE;
+
+typedef struct _COMPATIBILITY_CONTEXT_ELEMENT {
+  GUID Id;
+  ACTCTX_COMPATIBILITY_ELEMENT_TYPE Type;
+} COMPATIBILITY_CONTEXT_ELEMENT, *PCOMPATIBILITY_CONTEXT_ELEMENT;
+
+typedef struct _ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION {
+  DWORD ElementCount;
+  COMPATIBILITY_CONTEXT_ELEMENT Elements[];
+} ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION, *PACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION;
+
+
 #define ACTIVATION_CONTEXT_PATH_TYPE_NONE         1
 #define ACTIVATION_CONTEXT_PATH_TYPE_WIN32_FILE   2
 #define ACTIVATION_CONTEXT_PATH_TYPE_URL          3
index 396b442..545f5fe 100644 (file)
@@ -12,7 +12,7 @@
  *                  Samuel SerapiĆ³n
  */
 
-/* Based on Wine Staging 1.7.37 */
+/* Based on Wine 3.2-37c98396 */
 
 #include <rtl.h>
 #include <ntstrsafe.h>
@@ -441,15 +441,19 @@ enum assembly_type
 
 struct assembly
 {
-    enum assembly_type       type;
-    struct assembly_identity id;
-    struct file_info         manifest;
-    WCHAR                   *directory;
-    BOOL                     no_inherit;
-    struct dll_redirect     *dlls;
-    unsigned int             num_dlls;
-    unsigned int             allocated_dlls;
-    struct entity_array      entities;
+    enum assembly_type             type;
+    struct assembly_identity       id;
+    struct file_info               manifest;
+    WCHAR                         *directory;
+    BOOL                           no_inherit;
+    struct dll_redirect           *dlls;
+    unsigned int                   num_dlls;
+    unsigned int                   allocated_dlls;
+    struct entity_array            entities;
+    COMPATIBILITY_CONTEXT_ELEMENT *compat_contexts;
+    ULONG                          num_compat_contexts;
+    ACTCTX_REQUESTED_RUN_LEVEL     run_level;
+    ULONG                          ui_access;
 };
 
 enum context_sections
@@ -652,6 +656,16 @@ static const WCHAR staticW[] = {'s','t','a','t','i','c',0};
 static const WCHAR supportsmultilevelundoW[] = {'s','u','p','p','o','r','t','s','m','u','l','t','i','l','e','v','e','l','u','n','d','o',0};
 static const WCHAR wantstomenumergeW[] = {'w','a','n','t','s','t','o','m','e','n','u','m','e','r','g','e',0};
 
+static const WCHAR compatibilityW[] = {'c','o','m','p','a','t','i','b','i','l','i','t','y',0};
+static const WCHAR compatibilityNSW[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','c','o','m','p','a','t','i','b','i','l','i','t','y','.','v','1',0};
+static const WCHAR applicationW[] = {'a','p','p','l','i','c','a','t','i','o','n',0};
+static const WCHAR supportedOSW[] = {'s','u','p','p','o','r','t','e','d','O','S',0};
+static const WCHAR IdW[] = {'I','d',0};
+static const WCHAR requestedExecutionLevelW[] = {'r','e','q','u','e','s','t','e','d','E','x','e','c','u','t','i','o','n','L','e','v','e','l',0};
+static const WCHAR requestedPrivilegesW[] = {'r','e','q','u','e','s','t','e','d','P','r','i','v','i','l','e','g','e','s',0};
+static const WCHAR securityW[] = {'s','e','c','u','r','i','t','y',0};
+static const WCHAR trustInfoW[] = {'t','r','u','s','t','I','n','f','o',0};
+
 struct olemisc_entry
 {
     const WCHAR *name;
@@ -827,6 +841,25 @@ static struct dll_redirect* add_dll_redirect(struct assembly* assembly)
     return &assembly->dlls[assembly->num_dlls++];
 }
 
+static PCOMPATIBILITY_CONTEXT_ELEMENT add_compat_context(struct assembly* assembly)
+{
+    void *ptr;
+    if (assembly->num_compat_contexts)
+    {
+        unsigned int new_count = assembly->num_compat_contexts + 1;
+        ptr = RtlReAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+                                 assembly->compat_contexts,
+                                 new_count * sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
+    }
+    else
+    {
+        ptr = RtlAllocateHeap( RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMPATIBILITY_CONTEXT_ELEMENT) );
+    }
+    if (!ptr) return NULL;
+    assembly->compat_contexts = ptr;
+    return &assembly->compat_contexts[assembly->num_compat_contexts++];
+}
+
 static void free_assembly_identity(struct assembly_identity *ai)
 {
     RtlFreeHeap( RtlGetProcessHeap(), 0, ai->name );
@@ -1118,6 +1151,7 @@ static void actctx_release( ACTIVATION_CONTEXT *actctx )
             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->dlls );
             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->manifest.info );
             RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->directory );
+            RtlFreeHeap( RtlGetProcessHeap(), 0, assembly->compat_contexts );
             free_entity_array( &assembly->entities );
             free_assembly_identity(&assembly->id);
         }
@@ -2319,6 +2353,229 @@ static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct
     return ret;
 }
 
+static BOOL parse_compatibility_application_elem(xmlbuf_t* xmlbuf, struct assembly* assembly,
+                                                 struct actctx_loader* acl)
+{
+    xmlstr_t attr_name, attr_value, elem;
+    BOOL end = FALSE, ret = TRUE, error;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, applicationW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else if (xmlstr_cmp(&elem, supportedOSW))
+        {
+            while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+            {
+                if (xmlstr_cmp(&attr_name, IdW))
+                {
+                    UNICODE_STRING str;
+                    COMPATIBILITY_CONTEXT_ELEMENT* compat;
+                    GUID compat_id;
+                    str.Buffer = (PWSTR)attr_value.ptr;
+                    str.Length = str.MaximumLength = (USHORT)attr_value.len * sizeof(WCHAR);
+                    if (RtlGUIDFromString(&str, &compat_id) == STATUS_SUCCESS)
+                    {
+                        if (!(compat = add_compat_context(assembly))) return FALSE;
+                        compat->Type = ACTCX_COMPATIBILITY_ELEMENT_TYPE_OS;
+                        compat->Id = compat_id;
+                    }
+                    else
+                    {
+                        UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
+                        DPRINT1("Invalid guid %wZ\n", &attr_valueU);
+                    }
+                }
+                else
+                {
+                    UNICODE_STRING attr_nameU = xmlstr2unicode(&attr_name);
+                    UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
+                    DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+                }
+            }
+        }
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown elem %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+
+    return ret;
+}
+
+static BOOL parse_compatibility_elem(xmlbuf_t* xmlbuf, struct assembly* assembly,
+                                     struct actctx_loader* acl)
+{
+    xmlstr_t elem;
+    BOOL ret = TRUE;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, compatibilityW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else if (xmlstr_cmp(&elem, applicationW))
+        {
+            ret = parse_compatibility_application_elem(xmlbuf, assembly, acl);
+        }
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown elem %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+    return ret;
+}
+
+static BOOL parse_requested_execution_level_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
+{
+    static const WCHAR levelW[] = {'l','e','v','e','l',0};
+    static const WCHAR asInvokerW[] = {'a','s','I','n','v','o','k','e','r',0};
+    static const WCHAR requireAdministratorW[] = {'r','e','q','u','i','r','e','A','d','m','i','n','i','s','t','r','a','t','o','r',0};
+    static const WCHAR highestAvailableW[] = {'h','i','g','h','e','s','t','A','v','a','i','l','a','b','l','e',0};
+    static const WCHAR uiAccessW[] = {'u','i','A','c','c','e','s','s',0};
+    static const WCHAR falseW[] = {'f','a','l','s','e',0};
+    static const WCHAR trueW[] = {'t','r','u','e',0};
+
+    xmlstr_t attr_name, attr_value, elem;
+    BOOL end = FALSE, ret = TRUE, error;
+
+    /* Multiple requestedExecutionLevel elements are not supported. */
+    if (assembly->run_level != ACTCTX_RUN_LEVEL_UNSPECIFIED)
+        return FALSE;
+
+    while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+    {
+        UNICODE_STRING attr_nameU = xmlstr2unicode(&attr_name);
+        UNICODE_STRING attr_valueU = xmlstr2unicode(&attr_value);
+        if (xmlstr_cmp(&attr_name, levelW))
+        {
+            if (xmlstr_cmpi(&attr_value, asInvokerW))
+                assembly->run_level = ACTCTX_RUN_LEVEL_AS_INVOKER;
+            else if (xmlstr_cmpi(&attr_value, highestAvailableW))
+                assembly->run_level = ACTCTX_RUN_LEVEL_HIGHEST_AVAILABLE;
+            else if (xmlstr_cmpi(&attr_value, requireAdministratorW))
+                assembly->run_level = ACTCTX_RUN_LEVEL_REQUIRE_ADMIN;
+            else
+                DPRINT1("unknown execution level: %wZ\n", &attr_valueU);
+        }
+        else if (xmlstr_cmp(&attr_name, uiAccessW))
+        {
+            if (xmlstr_cmpi(&attr_value, falseW))
+                assembly->ui_access = FALSE;
+            else if (xmlstr_cmpi(&attr_value, trueW))
+                assembly->ui_access = TRUE;
+            else
+                DPRINT1("unknown uiAccess value: %wZ\n", &attr_valueU);
+        }
+        else
+            DPRINT1("unknown attr %wZ=%wZ\n", &attr_nameU, &attr_valueU);
+    }
+
+    if (error) return FALSE;
+    if (end) return TRUE;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, requestedExecutionLevelW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown element %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+
+    return ret;
+}
+
+static BOOL parse_requested_privileges_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct actctx_loader *acl)
+{
+    xmlstr_t elem;
+    BOOL ret = TRUE;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, requestedPrivilegesW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else if (xmlstr_cmp(&elem, requestedExecutionLevelW))
+            ret = parse_requested_execution_level_elem(xmlbuf, assembly, acl);
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown elem %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+
+    return ret;
+}
+
+static BOOL parse_security_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl)
+{
+    xmlstr_t elem;
+    BOOL ret = TRUE;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, securityW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else if (xmlstr_cmp(&elem, requestedPrivilegesW))
+            ret = parse_requested_privileges_elem(xmlbuf, assembly, acl);
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown elem %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+
+    return ret;
+}
+
+static BOOL parse_trust_info_elem(xmlbuf_t *xmlbuf, struct assembly *assembly, struct actctx_loader *acl)
+{
+    xmlstr_t elem;
+    BOOL ret = TRUE;
+
+    while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
+    {
+        if (xmlstr_cmp_end(&elem, trustInfoW))
+        {
+            ret = parse_end_element(xmlbuf);
+            break;
+        }
+        else if (xmlstr_cmp(&elem, securityW))
+            ret = parse_security_elem(xmlbuf, assembly, acl);
+        else
+        {
+            UNICODE_STRING elemU = xmlstr2unicode(&elem);
+            DPRINT1("unknown elem %wZ\n", &elemU);
+            ret = parse_unknown_elem(xmlbuf, &elem);
+        }
+    }
+
+    return ret;
+}
+
 static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
                                 struct assembly* assembly,
                                 struct assembly_identity* expected_ai)
@@ -2411,6 +2668,11 @@ static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
         {
             ret = parse_clr_surrogate_elem(xmlbuf, assembly, acl);
         }
+        else if (xml_elem_cmp(&elem, trustInfoW, asmv2W) ||
+                 xml_elem_cmp(&elem, trustInfoW, asmv1W))
+        {
+            ret = parse_trust_info_elem(xmlbuf, assembly, acl);
+        }
         else if (xml_elem_cmp(&elem, assemblyIdentityW, asmv1W))
         {
             if (!parse_assembly_identity_elem(xmlbuf, acl->actctx, &assembly->id)) return FALSE;
@@ -2440,12 +2702,10 @@ static BOOL parse_assembly_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl,
                 }
             }
         }
-#ifdef __REACTOS__
-        else if (xml_elem_cmp(&elem, L"trustInfo", asmv1W))
+        else if (xml_elem_cmp(&elem, compatibilityW, compatibilityNSW))
         {
-            ret = parse_unknown_elem(xmlbuf, &elem);
+            ret = parse_compatibility_elem(xmlbuf, assembly, acl);
         }
-#endif
         else
         {
             attr_nameU = xmlstr2unicode(&elem);
@@ -5273,6 +5533,55 @@ NTSTATUS NTAPI RtlQueryInformationActivationContext( ULONG flags, HANDLE handle,
         }
         break;
 
+    case CompatibilityInformationInActivationContext:
+        {
+            /*ACTIVATION_CONTEXT_COMPATIBILITY_INFORMATION*/DWORD *acci = buffer;
+            COMPATIBILITY_CONTEXT_ELEMENT *elements;
+            struct assembly *assembly = NULL;
+            ULONG num_compat_contexts = 0, n;
+            SIZE_T len;
+
+            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
+
+            if (actctx->num_assemblies) assembly = actctx->assemblies;
+
+            if (assembly)
+                num_compat_contexts = assembly->num_compat_contexts;
+            len = sizeof(*acci) + num_compat_contexts * sizeof(COMPATIBILITY_CONTEXT_ELEMENT);
+
+            if (retlen) *retlen = len;
+            if (!buffer || bufsize < len) return STATUS_BUFFER_TOO_SMALL;
+
+            *acci = num_compat_contexts;
+            elements = (COMPATIBILITY_CONTEXT_ELEMENT*)(acci + 1);
+            for (n = 0; n < num_compat_contexts; ++n)
+            {
+                elements[n] = assembly->compat_contexts[n];
+            }
+        }
+        break;
+
+    case RunlevelInformationInActivationContext:
+        {
+            ACTIVATION_CONTEXT_RUN_LEVEL_INFORMATION *acrli = buffer;
+            struct assembly *assembly;
+            SIZE_T len;
+
+            if (!(actctx = check_actctx(handle))) return STATUS_INVALID_PARAMETER;
+
+            len = sizeof(*acrli);
+            if (retlen) *retlen = len;
+            if (!buffer || bufsize < len)
+                return STATUS_BUFFER_TOO_SMALL;
+
+            assembly = actctx->assemblies;
+
+            acrli->ulFlags  = 0;
+            acrli->RunLevel = assembly ? assembly->run_level : ACTCTX_RUN_LEVEL_UNSPECIFIED;
+            acrli->UiAccess = assembly ? assembly->ui_access : 0;
+        }
+        break;
+
     default:
         DPRINT( "class %u not implemented\n", class );
         return STATUS_NOT_IMPLEMENTED;