ntdll: Implement compatible typelib section.

This commit is contained in:
Nikolay Sivov 2013-08-23 09:48:34 +04:00 committed by Alexandre Julliard
parent 1ca7eb649c
commit 36acd61447
2 changed files with 296 additions and 17 deletions

View file

@ -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,

View file

@ -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
<data>
This section doesn't seem to carry any payload data except dll names.
- typelib section format:
<section header>
<module names[]>
<index[]>
<data[]> --- <data>
<helpstring>
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, &section);
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;
}