From 36acd61447904f5b59fe1df45161a19935abd547 Mon Sep 17 00:00:00 2001 From: Nikolay Sivov Date: Fri, 23 Aug 2013 09:48:34 +0400 Subject: [PATCH] ntdll: Implement compatible typelib section. --- dlls/kernel32/tests/actctx.c | 2 - dlls/ntdll/actctx.c | 311 +++++++++++++++++++++++++++++++++-- 2 files changed, 296 insertions(+), 17 deletions(-) diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index bd8ab13c321..1a53749c63e 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -1319,9 +1319,7 @@ static void test_typelib_section(void) ret = pFindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, &IID_TlibTest, &data); -todo_wine ok(ret, "got %d\n", ret); - if (!ret) return; ret = pFindActCtxSectionGuid(0, NULL, ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION, diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 37ab11b5b87..da421fe5057 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -51,7 +51,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(actctx); ACTCTX_FLAG_HMODULE_VALID ) #define ACTCTX_MAGIC 0xC07E3E11 -#define SECTION_MAGIC 0x64487353 +#define STRSECTION_MAGIC 0x64487353 /* dHsS */ +#define GUIDSECTION_MAGIC 0x64487347 /* dHsG */ /* we don't want to include winuser.h */ #define RT_MANIFEST ((ULONG_PTR)24) @@ -122,6 +123,26 @@ struct string_index ULONG rosterindex; }; +struct guidsection_header +{ + DWORD magic; + ULONG size; + DWORD unk[3]; + ULONG count; + ULONG index_offset; + DWORD unk2; + ULONG names_offset; + ULONG names_len; +}; + +struct guid_index +{ + GUID guid; + ULONG data_offset; + ULONG data_len; + ULONG rosterindex; +}; + struct wndclass_redirect_data { ULONG size; @@ -139,6 +160,20 @@ struct dllredirect_data DWORD res[3]; }; +struct tlibredirect_data +{ + ULONG size; + DWORD res; + ULONG name_len; + ULONG name_offset; + LANGID langid; + WORD flags; + ULONG help_len; + ULONG help_offset; + WORD major_version; + WORD minor_version; +}; + /* Sections structure. @@ -177,6 +212,21 @@ struct dllredirect_data This section doesn't seem to carry any payload data except dll names. + + - typelib section format: + +
+ + + --- + + + Header is fixed length, index is an array of fixed length 'struct guid_index'. + All strings are WCHAR, null terminated, 4-bytes aligned. Module names part is + 4-bytes aligned as a whole. + + Module name offsets are relative to section, helpstring offset is relative to data + structure itself. */ struct entity @@ -254,8 +304,9 @@ struct assembly enum context_sections { - WINDOWCLASS_SECTION = 1, - DLLREDIRECT_SECTION = 2 + WINDOWCLASS_SECTION = 1, + DLLREDIRECT_SECTION = 2, + TLIBREDIRECT_SECTION = 4 }; typedef struct _ACTIVATION_CONTEXT @@ -269,8 +320,9 @@ typedef struct _ACTIVATION_CONTEXT unsigned int allocated_assemblies; /* section data */ DWORD sections; - struct strsection_header *wndclass_section; - struct strsection_header *dllredirect_section; + struct strsection_header *wndclass_section; + struct strsection_header *dllredirect_section; + struct guidsection_header *tlib_section; } ACTIVATION_CONTEXT; struct actctx_loader @@ -1156,7 +1208,7 @@ error: return FALSE; } -static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll) +static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader* acl) { xmlstr_t attr_name, attr_value; BOOL end = FALSE, error; @@ -1189,7 +1241,12 @@ static BOOL parse_typelib_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll) } } - if (error || end) return end; + if (error) return FALSE; + + acl->actctx->sections |= TLIBREDIRECT_SECTION; + + if (end) return TRUE; + return parse_expect_end_elem(xmlbuf, typelibW, asmv1W); } @@ -1555,7 +1612,7 @@ static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct } else if (xmlstr_cmp(&elem, typelibW)) { - ret = parse_typelib_elem(xmlbuf, dll); + ret = parse_typelib_elem(xmlbuf, dll, acl); } else if (xmlstr_cmp(&elem, windowClassW)) { @@ -2355,7 +2412,7 @@ static NTSTATUS build_dllredirect_section(ACTIVATION_CONTEXT* actctx, struct str if (!header) return STATUS_NO_MEMORY; memset(header, 0, sizeof(*header)); - header->magic = SECTION_MAGIC; + header->magic = STRSECTION_MAGIC; header->size = sizeof(*header); header->count = dll_count; header->index_offset = sizeof(*header); @@ -2434,6 +2491,26 @@ static struct string_index *find_string_index(const struct strsection_header *se return index; } +static struct guid_index *find_guid_index(const struct guidsection_header *section, const GUID *guid) +{ + struct guid_index *iter, *index = NULL; + ULONG i; + + iter = (struct guid_index*)((BYTE*)section + section->index_offset); + + for (i = 0; i < section->count; i++) + { + if (!memcmp(guid, &iter->guid, sizeof(*guid))) + { + index = iter; + break; + } + iter++; + } + + return index; +} + static inline struct dllredirect_data *get_dllredirect_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index) { return (struct dllredirect_data*)((BYTE*)ctxt->dllredirect_section + index->data_offset); @@ -2536,7 +2613,7 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct strsec if (!header) return STATUS_NO_MEMORY; memset(header, 0, sizeof(*header)); - header->magic = SECTION_MAGIC; + header->magic = STRSECTION_MAGIC; header->size = sizeof(*header); header->count = class_count; header->index_offset = sizeof(*header); @@ -2688,6 +2765,174 @@ static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRI return STATUS_SUCCESS; } +static NTSTATUS build_tlib_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section) +{ + unsigned int i, j, k, total_len = 0, tlib_count = 0, names_len = 0; + struct guidsection_header *header; + ULONG module_offset, data_offset; + struct tlibredirect_data *data; + struct guid_index *index; + + /* compute section length */ + for (i = 0; i < actctx->num_assemblies; i++) + { + struct assembly *assembly = &actctx->assemblies[i]; + for (j = 0; j < assembly->num_dlls; j++) + { + struct dll_redirect *dll = &assembly->dlls[j]; + for (k = 0; k < dll->entities.num; k++) + { + struct entity *entity = &dll->entities.base[k]; + if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION) + { + /* each entry needs index, data and string data for module name and help string */ + total_len += sizeof(*index); + total_len += sizeof(*data); + /* help string is stored separately */ + if (*entity->u.typelib.helpdir) + total_len += aligned_string_len((strlenW(entity->u.typelib.helpdir)+1)*sizeof(WCHAR)); + + /* module names are packed one after another */ + names_len += (strlenW(dll->name)+1)*sizeof(WCHAR); + + tlib_count++; + } + } + } + } + + total_len += aligned_string_len(names_len); + total_len += sizeof(*header); + + header = RtlAllocateHeap(GetProcessHeap(), 0, total_len); + if (!header) return STATUS_NO_MEMORY; + + memset(header, 0, sizeof(*header)); + header->magic = GUIDSECTION_MAGIC; + header->size = sizeof(*header); + header->count = tlib_count; + header->index_offset = sizeof(*header) + aligned_string_len(names_len); + index = (struct guid_index*)((BYTE*)header + header->index_offset); + module_offset = sizeof(*header); + data_offset = header->index_offset + tlib_count*sizeof(*index); + + for (i = 0; i < actctx->num_assemblies; i++) + { + struct assembly *assembly = &actctx->assemblies[i]; + for (j = 0; j < assembly->num_dlls; j++) + { + struct dll_redirect *dll = &assembly->dlls[j]; + for (k = 0; k < dll->entities.num; k++) + { + struct entity *entity = &dll->entities.base[k]; + if (entity->kind == ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION) + { + ULONG module_len, help_len; + UNICODE_STRING str; + WCHAR *ptrW; + + if (*entity->u.typelib.helpdir) + help_len = strlenW(entity->u.typelib.helpdir)*sizeof(WCHAR); + else + help_len = 0; + + module_len = strlenW(dll->name)*sizeof(WCHAR); + + /* setup new index entry */ + RtlInitUnicodeString(&str, entity->u.typelib.tlbid); + RtlGUIDFromString(&str, &index->guid); + index->data_offset = data_offset; + index->data_len = sizeof(*data) + aligned_string_len(help_len); + index->rosterindex = i + 1; + + /* setup data */ + data = (struct tlibredirect_data*)((BYTE*)header + index->data_offset); + data->size = sizeof(*data); + data->res = 0; + data->name_len = module_len; + data->name_offset = module_offset; + /* FIXME: resourceid handling is really weird, and it doesn't seem to be useful */ + data->langid = 0; + data->flags = entity->u.typelib.flags; + data->help_len = help_len; + data->help_offset = sizeof(*data); + data->major_version = entity->u.typelib.major; + data->minor_version = entity->u.typelib.minor; + + /* module name */ + ptrW = (WCHAR*)((BYTE*)header + data->name_offset); + memcpy(ptrW, dll->name, data->name_len); + ptrW[data->name_len/sizeof(WCHAR)] = 0; + + /* help string */ + if (data->help_len) + { + ptrW = (WCHAR*)((BYTE*)data + data->help_offset); + memcpy(ptrW, entity->u.typelib.helpdir, data->help_len); + ptrW[data->help_len/sizeof(WCHAR)] = 0; + } + + data_offset += sizeof(*data); + if (help_len) + data_offset += aligned_string_len(help_len + sizeof(WCHAR)); + + module_offset += module_len + sizeof(WCHAR); + + index++; + } + } + } + } + + *section = header; + + return STATUS_SUCCESS; +} + +static inline struct tlibredirect_data *get_tlib_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index) +{ + return (struct tlibredirect_data*)((BYTE*)actctx->tlib_section + index->data_offset); +} + +static NTSTATUS find_tlib_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data) +{ + struct guid_index *index = NULL; + struct tlibredirect_data *tlib; + + if (!(actctx->sections & TLIBREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND; + + if (!actctx->tlib_section) + { + struct guidsection_header *section; + + NTSTATUS status = build_tlib_section(actctx, §ion); + if (status) return status; + + if (interlocked_cmpxchg_ptr((void**)&actctx->tlib_section, section, NULL)) + RtlFreeHeap(GetProcessHeap(), 0, section); + } + + index = find_guid_index(actctx->tlib_section, guid); + if (!index) return STATUS_SXS_KEY_NOT_FOUND; + + tlib = get_tlib_data(actctx, index); + + data->ulDataFormatVersion = 1; + data->lpData = tlib; + /* full length includes string length with nulls */ + data->ulLength = tlib->size + tlib->help_len + sizeof(WCHAR); + data->lpSectionGlobalData = NULL; + data->ulSectionGlobalDataLength = 0; + data->lpSectionBase = actctx->tlib_section; + data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->tlib_section ); + data->hActCtx = NULL; + + if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG)) + data->ulAssemblyRosterIndex = index->rosterindex; + + return STATUS_SUCCESS; +} + static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind, const UNICODE_STRING *section_name, DWORD flags, PACTCTX_SECTION_KEYED_DATA data) @@ -2702,9 +2947,6 @@ static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind, case ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION: status = find_window_class(actctx, section_name, data); break; - case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION: - case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION: - case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION: case ACTIVATION_CONTEXT_SECTION_COM_PROGID_REDIRECTION: case ACTIVATION_CONTEXT_SECTION_GLOBAL_OBJECT_RENAME_TABLE: case ACTIVATION_CONTEXT_SECTION_CLR_SURROGATES: @@ -2725,6 +2967,35 @@ static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind, return STATUS_SUCCESS; } +static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind, + const GUID *guid, DWORD flags, PACTCTX_SECTION_KEYED_DATA data) +{ + NTSTATUS status; + + switch (section_kind) + { + case ACTIVATION_CONTEXT_SECTION_COM_TYPE_LIBRARY_REDIRECTION: + status = find_tlib_redirection(actctx, guid, data); + break; + case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION: + case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION: + FIXME("Unsupported yet section_kind %x\n", section_kind); + return STATUS_SXS_SECTION_NOT_FOUND; + default: + WARN("Unknown section_kind %x\n", section_kind); + return STATUS_SXS_SECTION_NOT_FOUND; + } + + if (status != STATUS_SUCCESS) return status; + + if (flags & FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX) + { + actctx_addref(actctx); + data->hActCtx = actctx; + } + return STATUS_SUCCESS; +} + /* initialize the activation context for the current process */ void actctx_init(void) { @@ -3244,8 +3515,9 @@ NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *ex const GUID *guid, void *ptr ) { ACTCTX_SECTION_KEYED_DATA *data = ptr; + NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND; - FIXME("%08x %s %u %s %p: stub\n", flags, debugstr_guid(extguid), section_kind, debugstr_guid(guid), data); + TRACE("%08x %s %u %s %p\n", flags, debugstr_guid(extguid), section_kind, debugstr_guid(guid), data); if (extguid) { @@ -3262,5 +3534,14 @@ NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *ex if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid) return STATUS_INVALID_PARAMETER; - return STATUS_NOT_IMPLEMENTED; + if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) + { + ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext); + if (actctx) status = find_guid( actctx, section_kind, guid, flags, data ); + } + + if (status != STATUS_SUCCESS) + status = find_guid( process_actctx, section_kind, guid, flags, data ); + + return status; }