ntdll: Implement compatible comClass section.

oldstable
Nikolay Sivov 2013-08-30 08:03:28 +04:00 committed by Alexandre Julliard
parent 75fbef2ded
commit 88070accd2
2 changed files with 278 additions and 13 deletions

View File

@ -1127,13 +1127,7 @@ static void test_find_com_redirection(HANDLE handle, const GUID *clsid, const GU
ret = pFindActCtxSectionGuid(0, NULL, ret = pFindActCtxSectionGuid(0, NULL,
ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION,
clsid, &data); clsid, &data);
todo_wine
ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError()); ok_(__FILE__, line)(ret, "FindActCtxSectionGuid failed: %u\n", GetLastError());
if(!ret)
{
skip("couldn't find guid %s\n", debugstr_guid(clsid));
return;
}
comclass = (struct comclassredirect_data*)data.lpData; comclass = (struct comclassredirect_data*)data.lpData;
@ -1184,10 +1178,11 @@ todo_wine
ok_(__FILE__, line)(comclass->miscstatusdocprint != 0, "got miscstatusdocprint 0x%08x\n", comclass->miscstatusdocprint); ok_(__FILE__, line)(comclass->miscstatusdocprint != 0, "got miscstatusdocprint 0x%08x\n", comclass->miscstatusdocprint);
} }
} }
todo_wine {
ok_(__FILE__, line)(data.lpSectionGlobalData != NULL, "data.lpSectionGlobalData == NULL\n"); ok_(__FILE__, line)(data.lpSectionGlobalData != NULL, "data.lpSectionGlobalData == NULL\n");
ok_(__FILE__, line)(data.ulSectionGlobalDataLength > 0, "data.ulSectionGlobalDataLength=%u\n", ok_(__FILE__, line)(data.ulSectionGlobalDataLength > 0, "data.ulSectionGlobalDataLength=%u\n",
data.ulSectionGlobalDataLength); data.ulSectionGlobalDataLength);
}
ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n"); ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n");
ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n", ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n",
data.ulSectionTotalLength); data.ulSectionTotalLength);

View File

@ -219,6 +219,29 @@ enum comclass_miscfields
MiscStatusDocPrint = 16 MiscStatusDocPrint = 16
}; };
struct comclassredirect_data
{
ULONG size;
BYTE res;
BYTE miscmask;
BYTE res1[2];
DWORD model;
GUID clsid;
GUID alias;
GUID clsid2;
GUID tlbid;
ULONG name_len;
ULONG name_offset;
ULONG progid_len;
ULONG progid_offset;
DWORD res2[2]; /* this was likely reserved for 'description' but not used */
DWORD miscstatus;
DWORD miscstatuscontent;
DWORD miscstatusthumbnail;
DWORD miscstatusicon;
DWORD miscstatusdocprint;
};
/* /*
Sections structure. Sections structure.
@ -272,6 +295,21 @@ enum comclass_miscfields
Module name offsets are relative to section, helpstring offset is relative to data Module name offsets are relative to section, helpstring offset is relative to data
structure itself. structure itself.
- comclass section format:
<section header>
<module names[]>
<index[]>
<data[]> --- <data>
<progid>
This section uses two index records per comclass, one entry contains original guid
as specified by context, another one has a generated guid. Index and strings handling
is similar to typelib sections.
Module name offsets are relative to section, progid offset is relative to data
structure itself.
*/ */
struct entity struct entity
@ -357,9 +395,10 @@ struct assembly
enum context_sections enum context_sections
{ {
WINDOWCLASS_SECTION = 1, WINDOWCLASS_SECTION = 1,
DLLREDIRECT_SECTION = 2, DLLREDIRECT_SECTION = 2,
TLIBREDIRECT_SECTION = 4 TLIBREDIRECT_SECTION = 4,
SERVERREDIRECT_SECTION = 8
}; };
typedef struct _ACTIVATION_CONTEXT typedef struct _ACTIVATION_CONTEXT
@ -376,6 +415,7 @@ typedef struct _ACTIVATION_CONTEXT
struct strsection_header *wndclass_section; struct strsection_header *wndclass_section;
struct strsection_header *dllredirect_section; struct strsection_header *dllredirect_section;
struct guidsection_header *tlib_section; struct guidsection_header *tlib_section;
struct guidsection_header *comserver_section;
} ACTIVATION_CONTEXT; } ACTIVATION_CONTEXT;
struct actctx_loader struct actctx_loader
@ -918,6 +958,7 @@ static void actctx_release( ACTIVATION_CONTEXT *actctx )
RtlFreeHeap( GetProcessHeap(), 0, actctx->dllredirect_section ); RtlFreeHeap( GetProcessHeap(), 0, actctx->dllredirect_section );
RtlFreeHeap( GetProcessHeap(), 0, actctx->wndclass_section ); RtlFreeHeap( GetProcessHeap(), 0, actctx->wndclass_section );
RtlFreeHeap( GetProcessHeap(), 0, actctx->tlib_section ); RtlFreeHeap( GetProcessHeap(), 0, actctx->tlib_section );
RtlFreeHeap( GetProcessHeap(), 0, actctx->comserver_section );
actctx->magic = 0; actctx->magic = 0;
RtlFreeHeap( GetProcessHeap(), 0, actctx ); RtlFreeHeap( GetProcessHeap(), 0, actctx );
} }
@ -1261,7 +1302,7 @@ static DWORD parse_com_class_misc(const xmlstr_t *value)
return flags; return flags;
} }
static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll) static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll, struct actctx_loader *acl)
{ {
xmlstr_t elem, attr_name, attr_value; xmlstr_t elem, attr_name, attr_value;
BOOL ret, end = FALSE, error; BOOL ret, end = FALSE, error;
@ -1314,7 +1355,11 @@ static BOOL parse_com_class_elem(xmlbuf_t* xmlbuf, struct dll_redirect* dll)
} }
} }
if (error || end) return end; if (error) return FALSE;
acl->actctx->sections |= SERVERREDIRECT_SECTION;
if (end) return TRUE;
while ((ret = next_xml_elem(xmlbuf, &elem))) while ((ret = next_xml_elem(xmlbuf, &elem)))
{ {
@ -1818,7 +1863,7 @@ static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct
} }
else if (xmlstr_cmp(&elem, comClassW)) else if (xmlstr_cmp(&elem, comClassW))
{ {
ret = parse_com_class_elem(xmlbuf, dll); ret = parse_com_class_elem(xmlbuf, dll, acl);
} }
else if (xmlstr_cmp(&elem, comInterfaceProxyStubW)) else if (xmlstr_cmp(&elem, comInterfaceProxyStubW))
{ {
@ -3152,6 +3197,229 @@ static NTSTATUS find_tlib_redirection(ACTIVATION_CONTEXT* actctx, const GUID *gu
return STATUS_SUCCESS; return STATUS_SUCCESS;
} }
static void generate_uuid(ULONG *seed, GUID *guid)
{
ULONG *ptr = (ULONG*)guid;
int i;
/* GUID is 16 bytes long */
for (i = 0; i < sizeof(GUID)/sizeof(ULONG); i++, ptr++)
*ptr = RtlUniform(seed);
guid->Data3 &= 0x0fff;
guid->Data3 |= (4 << 12);
guid->Data4[0] &= 0x3f;
guid->Data4[0] |= 0x80;
}
static NTSTATUS build_comserver_section(ACTIVATION_CONTEXT* actctx, struct guidsection_header **section)
{
unsigned int i, j, k, total_len = 0, class_count = 0, names_len = 0;
struct guid_index *index, *alias_index;
struct comclassredirect_data *data;
struct guidsection_header *header;
ULONG module_offset, data_offset;
ULONG seed;
/* 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_SERVER_REDIRECTION)
{
/* each entry needs two index entries, extra one goes for alias GUID */
total_len += 2*sizeof(*index);
/* to save some memory we don't allocated two data structures,
instead alias index and normal index point to the same data structure */
total_len += sizeof(*data);
/* help string is stored separately */
if (*entity->u.comclass.progid)
total_len += aligned_string_len((strlenW(entity->u.comclass.progid)+1)*sizeof(WCHAR));
/* module names are packed one after another */
names_len += (strlenW(dll->name)+1)*sizeof(WCHAR);
class_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 = 2*class_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 + 2*class_count*sizeof(*index);
seed = NtGetTickCount();
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_SERVER_REDIRECTION)
{
ULONG module_len, progid_len;
UNICODE_STRING str;
WCHAR *ptrW;
if (*entity->u.comclass.progid)
progid_len = strlenW(entity->u.comclass.progid)*sizeof(WCHAR);
else
progid_len = 0;
module_len = strlenW(dll->name)*sizeof(WCHAR);
/* setup new index entry */
RtlInitUnicodeString(&str, entity->u.comclass.clsid);
RtlGUIDFromString(&str, &index->guid);
index->data_offset = data_offset;
index->data_len = sizeof(*data) + aligned_string_len(progid_len);
index->rosterindex = i + 1;
/* Setup new index entry for alias guid. Alias index records are placed after
normal records, so normal guids are hit first on search */
alias_index = index + class_count;
generate_uuid(&seed, &alias_index->guid);
alias_index->data_offset = index->data_offset;
alias_index->data_len = index->data_len;
alias_index->rosterindex = index->rosterindex;
/* setup data */
data = (struct comclassredirect_data*)((BYTE*)header + index->data_offset);
data->size = sizeof(*data);
data->res = 0;
data->res1[0] = 0;
data->res1[1] = 0;
data->model = entity->u.comclass.model;
data->clsid = index->guid;
data->alias = alias_index->guid;
data->clsid2 = data->clsid;
if (entity->u.comclass.tlbid)
{
RtlInitUnicodeString(&str, entity->u.comclass.tlbid);
RtlGUIDFromString(&str, &data->tlbid);
}
else
memset(&data->tlbid, 0, sizeof(data->tlbid));
data->name_len = module_len;
data->name_offset = module_offset;
data->progid_len = progid_len;
data->progid_offset = sizeof(*data);
data->res2[0] = 0;
data->res2[1] = 0;
data->miscstatus = entity->u.comclass.miscstatus;
data->miscstatuscontent = entity->u.comclass.miscstatuscontent;
data->miscstatusthumbnail = entity->u.comclass.miscstatusthumbnail;
data->miscstatusicon = entity->u.comclass.miscstatusicon;
data->miscstatusdocprint = entity->u.comclass.miscstatusdocprint;
/* mask describes which misc* data is available */
data->miscmask = 0;
if (data->miscstatus)
data->miscmask |= MiscStatus;
if (data->miscstatuscontent)
data->miscmask |= MiscStatusContent;
if (data->miscstatusthumbnail)
data->miscmask |= MiscStatusThumbnail;
if (data->miscstatusicon)
data->miscmask |= MiscStatusIcon;
if (data->miscstatusdocprint)
data->miscmask |= MiscStatusDocPrint;
/* module name */
ptrW = (WCHAR*)((BYTE*)header + data->name_offset);
memcpy(ptrW, dll->name, data->name_len);
ptrW[data->name_len/sizeof(WCHAR)] = 0;
/* progid string */
if (data->progid_len)
{
ptrW = (WCHAR*)((BYTE*)data + data->progid_offset);
memcpy(ptrW, entity->u.comclass.progid, data->progid_len);
ptrW[data->progid_len/sizeof(WCHAR)] = 0;
}
data_offset += sizeof(*data);
if (progid_len)
data_offset += aligned_string_len(progid_len + sizeof(WCHAR));
module_offset += module_len + sizeof(WCHAR);
index++;
}
}
}
}
*section = header;
return STATUS_SUCCESS;
}
static inline struct comclassredirect_data *get_comclass_data(ACTIVATION_CONTEXT *actctx, struct guid_index *index)
{
return (struct comclassredirect_data*)((BYTE*)actctx->comserver_section + index->data_offset);
}
static NTSTATUS find_comserver_redirection(ACTIVATION_CONTEXT* actctx, const GUID *guid, ACTCTX_SECTION_KEYED_DATA* data)
{
struct comclassredirect_data *comclass;
struct guid_index *index = NULL;
if (!(actctx->sections & SERVERREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
if (!actctx->comserver_section)
{
struct guidsection_header *section;
NTSTATUS status = build_comserver_section(actctx, &section);
if (status) return status;
if (interlocked_cmpxchg_ptr((void**)&actctx->comserver_section, section, NULL))
RtlFreeHeap(GetProcessHeap(), 0, section);
}
index = find_guid_index(actctx->comserver_section, guid);
if (!index) return STATUS_SXS_KEY_NOT_FOUND;
comclass = get_comclass_data(actctx, index);
data->ulDataFormatVersion = 1;
data->lpData = comclass;
/* full length includes string length with nulls */
data->ulLength = comclass->size + comclass->progid_len + sizeof(WCHAR);
data->lpSectionGlobalData = NULL;
data->ulSectionGlobalDataLength = 0;
data->lpSectionBase = actctx->comserver_section;
data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->comserver_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, static NTSTATUS find_string(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
const UNICODE_STRING *section_name, const UNICODE_STRING *section_name,
DWORD flags, PACTCTX_SECTION_KEYED_DATA data) DWORD flags, PACTCTX_SECTION_KEYED_DATA data)
@ -3197,6 +3465,8 @@ static NTSTATUS find_guid(ACTIVATION_CONTEXT* actctx, ULONG section_kind,
status = find_tlib_redirection(actctx, guid, data); status = find_tlib_redirection(actctx, guid, data);
break; break;
case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION: case ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION:
status = find_comserver_redirection(actctx, guid, data);
break;
case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION: case ACTIVATION_CONTEXT_SECTION_COM_INTERFACE_REDIRECTION:
FIXME("Unsupported yet section_kind %x\n", section_kind); FIXME("Unsupported yet section_kind %x\n", section_kind);
return STATUS_SXS_SECTION_NOT_FOUND; return STATUS_SXS_SECTION_NOT_FOUND;