diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c
index ae82a07e880..234fa9d937f 100644
--- a/dlls/kernel32/tests/actctx.c
+++ b/dlls/kernel32/tests/actctx.c
@@ -105,7 +105,7 @@ static const char manifest_wndcls1[] =
""
""
""
-"wndClass1"
+"wndClass1"
"wndClass2"
""
"";
@@ -114,7 +114,7 @@ static const char manifest_wndcls2[] =
""
""
""
-"wndClass3"
+"wndClass3"
"wndClass4"
""
"";
@@ -1140,9 +1140,12 @@ todo_wine
static void test_wndclass_section(void)
{
+ static const WCHAR cls1W[] = {'1','.','2','.','3','.','4','!','w','n','d','C','l','a','s','s','1',0};
ACTCTX_SECTION_KEYED_DATA data, data2;
+ struct wndclass_redirect_data *classdata;
ULONG_PTR cookie;
HANDLE handle;
+ WCHAR *ptrW;
BOOL ret;
/* use two dependent manifests, each defines 2 window class redirects */
@@ -1178,6 +1181,15 @@ static void test_wndclass_section(void)
ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength,
data2.ulSectionTotalLength);
+ /* wndClass1 is versioned, wndClass3 is not */
+ classdata = (struct wndclass_redirect_data*)data.lpData;
+ ptrW = (WCHAR*)((BYTE*)data.lpData + classdata->name_offset);
+ ok(!lstrcmpW(ptrW, cls1W), "got %s\n", wine_dbgstr_w(ptrW));
+
+ classdata = (struct wndclass_redirect_data*)data2.lpData;
+ ptrW = (WCHAR*)((BYTE*)data2.lpData + classdata->name_offset);
+ ok(!lstrcmpW(ptrW, wndClass3W), "got %s\n", wine_dbgstr_w(ptrW));
+
ret = pDeactivateActCtx(0, cookie);
ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c
index 1561db8b4a9..d5f7055d96e 100644
--- a/dlls/ntdll/actctx.c
+++ b/dlls/ntdll/actctx.c
@@ -167,6 +167,7 @@ struct entity
struct
{
WCHAR *name;
+ BOOL versioned;
} class;
struct
{
@@ -279,6 +280,9 @@ static const WCHAR tlbidW[] = {'t','l','b','i','d',0};
static const WCHAR typeW[] = {'t','y','p','e',0};
static const WCHAR versionW[] = {'v','e','r','s','i','o','n',0};
static const WCHAR xmlnsW[] = {'x','m','l','n','s',0};
+static const WCHAR versionedW[] = {'v','e','r','s','i','o','n','e','d',0};
+static const WCHAR yesW[] = {'y','e','s',0};
+static const WCHAR noW[] = {'n','o',0};
static const WCHAR xmlW[] = {'?','x','m','l',0};
static const WCHAR manifestv1W[] = {'u','r','n',':','s','c','h','e','m','a','s','-','m','i','c','r','o','s','o','f','t','-','c','o','m',':','a','s','m','.','v','1',0};
@@ -1093,15 +1097,30 @@ static int get_assembly_version(struct assembly *assembly, WCHAR *ret)
static BOOL parse_window_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl)
{
- xmlstr_t elem, content;
- BOOL end = FALSE, ret = TRUE;
+ xmlstr_t elem, content, attr_name, attr_value;
+ BOOL end = FALSE, ret = TRUE, error;
struct entity* entity;
if (!(entity = add_entity(&dll->entities, ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)))
return FALSE;
- if (!parse_expect_no_attr(xmlbuf, &end)) return FALSE;
- if (end) return FALSE;
+ entity->u.class.versioned = TRUE;
+ while (next_xml_attr(xmlbuf, &attr_name, &attr_value, &error, &end))
+ {
+ if (xmlstr_cmp(&attr_name, versionedW))
+ {
+ if (xmlstr_cmpi(&attr_value, noW))
+ entity->u.class.versioned = FALSE;
+ else if (!xmlstr_cmpi(&attr_value, yesW))
+ return FALSE;
+ }
+ else
+ {
+ WARN("unknown attr %s=%s\n", debugstr_xmlstr(&attr_name), debugstr_xmlstr(&attr_value));
+ }
+ }
+
+ if (error || end) return end;
if (!parse_text_content(xmlbuf, &content)) return FALSE;
@@ -1318,7 +1337,6 @@ static BOOL parse_dependency_elem(xmlbuf_t* xmlbuf, struct actctx_loader* acl)
{
if (xmlstr_cmp(&attr_name, optionalW))
{
- static const WCHAR yesW[] = {'y','e','s',0};
optional = xmlstr_cmpi( &attr_value, yesW );
TRACE("optional=%s\n", debugstr_xmlstr(&attr_value));
}
@@ -2259,16 +2277,19 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
struct entity *entity = &dll->entities.base[k];
if (entity->kind == ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION)
{
- int class_len = strlenW(entity->u.class.name);
+ int class_len = strlenW(entity->u.class.name) + 1;
int len;
/* each class entry needs index, data and string data */
total_len += sizeof(struct wndclass_index);
total_len += sizeof(struct wndclass_redirect_data);
/* original name is stored separately */
- total_len += aligned_string_len((class_len+1)*sizeof(WCHAR));
+ total_len += aligned_string_len(class_len*sizeof(WCHAR));
/* versioned name and module name are stored one after another */
- len = get_assembly_version(assembly, NULL) + class_len + 2 /* null terminator and '!' separator */;
+ if (entity->u.class.versioned)
+ len = get_assembly_version(assembly, NULL) + class_len + 1 /* '!' separator */;
+ else
+ len = class_len;
len += strlenW(dll->name) + 1;
total_len += aligned_string_len(len*sizeof(WCHAR));
@@ -2314,7 +2335,10 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
/* include '!' separator too */
- versioned_len = (get_assembly_version(assembly, NULL) + 1)*sizeof(WCHAR) + str.Length;
+ if (entity->u.class.versioned)
+ versioned_len = (get_assembly_version(assembly, NULL) + 1)*sizeof(WCHAR) + str.Length;
+ else
+ versioned_len = str.Length;
module_len = strlenW(dll->name)*sizeof(WCHAR);
index->name_offset = name_offset;
@@ -2344,9 +2368,17 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
/* versioned name */
ptrW = (WCHAR*)((BYTE*)data + data->name_offset);
- get_assembly_version(assembly, ptrW);
- strcatW(ptrW, exclW);
- strcatW(ptrW, entity->u.class.name);
+ if (entity->u.class.versioned)
+ {
+ get_assembly_version(assembly, ptrW);
+ strcatW(ptrW, exclW);
+ strcatW(ptrW, entity->u.class.name);
+ }
+ else
+ {
+ memcpy(ptrW, entity->u.class.name, index->name_len);
+ ptrW[index->name_len/sizeof(WCHAR)] = 0;
+ }
name_offset += sizeof(*data);
name_offset += aligned_string_len(str.MaximumLength) + aligned_string_len(versioned_len + module_len + 2*sizeof(WCHAR));