ntdll: Implement compatible section for dll redirects.

This commit is contained in:
Nikolay Sivov 2013-08-04 18:21:09 +04:00 committed by Alexandre Julliard
parent cddea89d22
commit 2a5a8bc4a3
2 changed files with 334 additions and 137 deletions

View File

@ -108,6 +108,7 @@ static const char manifest_wndcls1[] =
"<windowClass versioned=\"yes\">wndClass1</windowClass>" "<windowClass versioned=\"yes\">wndClass1</windowClass>"
"<windowClass>wndClass2</windowClass>" "<windowClass>wndClass2</windowClass>"
"</file>" "</file>"
"<file name=\"testlib1_2.dll\" />"
"</assembly>"; "</assembly>";
static const char manifest_wndcls2[] = static const char manifest_wndcls2[] =
@ -117,6 +118,7 @@ static const char manifest_wndcls2[] =
"<windowClass versioned=\"no\">wndClass3</windowClass>" "<windowClass versioned=\"no\">wndClass3</windowClass>"
"<windowClass>wndClass4</windowClass>" "<windowClass>wndClass4</windowClass>"
"</file>" "</file>"
"<file name=\"testlib2_2.dll\" />"
"</assembly>"; "</assembly>";
static const char manifest_wndcls_main[] = static const char manifest_wndcls_main[] =
@ -754,101 +756,17 @@ static void test_create_fail(void)
test_create_and_fail(manifest2, wrong_depmanifest1, 0 ); test_create_and_fail(manifest2, wrong_depmanifest1, 0 );
} }
struct dllredirect_keyed_data struct strsection_header
{
ULONG size;
ULONG unk;
DWORD res[3];
};
static void test_find_dll_redirection(HANDLE handle, LPCWSTR libname, ULONG exid, int line)
{
ACTCTX_SECTION_KEYED_DATA data;
BOOL ret;
memset(&data, 0xfe, sizeof(data));
data.cbSize = sizeof(data);
ret = pFindActCtxSectionStringW(0, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
libname, &data);
ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError());
if(!ret)
{
skip("couldn't find %s\n",strw(libname));
return;
}
ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize);
ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion);
ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n");
ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength);
if (data.lpData)
{
struct dllredirect_keyed_data *dlldata = (struct dllredirect_keyed_data*)data.lpData;
todo_wine
ok_(__FILE__, line)(dlldata->size == data.ulLength, "got wrong size %d\n", dlldata->size);
if (dlldata->size == data.ulLength)
{
ok_(__FILE__, line)(dlldata->unk == 2, "got wrong field value %d\n", dlldata->unk);
ok_(__FILE__, line)(dlldata->res[0] == 0, "got wrong res[0] value %d\n", dlldata->res[0]);
ok_(__FILE__, line)(dlldata->res[1] == 0, "got wrong res[1] value %d\n", dlldata->res[1]);
ok_(__FILE__, line)(dlldata->res[2] == 0, "got wrong res[2] value %d\n", dlldata->res[2]);
}
}
ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n");
ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n",
data.ulSectionGlobalDataLength);
ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n");
/* ok_(__FILE__, line)(data.ulSectionTotalLength == ??, "data.ulSectionTotalLength=%u\n",
data.ulSectionTotalLength); */
ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx);
ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n",
data.ulAssemblyRosterIndex, exid);
memset(&data, 0xfe, sizeof(data));
data.cbSize = sizeof(data);
ret = pFindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
libname, &data);
ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError());
if(!ret)
{
skip("couldn't find\n");
return;
}
ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize);
ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion);
ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n");
ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength);
ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n");
ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n",
data.ulSectionGlobalDataLength);
ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n");
/* ok_(__FILE__, line)(data.ulSectionTotalLength == ?? , "data.ulSectionTotalLength=%u\n",
data.ulSectionTotalLength); */
ok_(__FILE__, line)(data.hActCtx == handle, "data.hActCtx=%p\n", data.hActCtx);
ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n",
data.ulAssemblyRosterIndex, exid);
pReleaseActCtx(handle);
}
struct wndclass_header
{ {
DWORD magic; DWORD magic;
DWORD unk1[4]; ULONG size;
DWORD unk1[3];
ULONG count; ULONG count;
ULONG index_offset; ULONG index_offset;
DWORD unk2[4]; DWORD unk2[4];
}; };
struct wndclass_index struct string_index
{ {
ULONG hash; ULONG hash;
ULONG name_offset; ULONG name_offset;
@ -868,10 +786,82 @@ struct wndclass_redirect_data
ULONG module_offset;/* container name offset */ ULONG module_offset;/* container name offset */
}; };
struct dllredirect_data
{
ULONG size;
ULONG unk;
DWORD res[3];
};
static void test_find_dll_redirection(HANDLE handle, LPCWSTR libname, ULONG exid, int line)
{
ACTCTX_SECTION_KEYED_DATA data;
BOOL ret;
memset(&data, 0xfe, sizeof(data));
data.cbSize = sizeof(data);
ret = pFindActCtxSectionStringW(0, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
libname, &data);
ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError());
if (!ret) return;
ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize);
ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion);
ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n");
ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength);
if (data.lpData)
{
struct dllredirect_data *dlldata = (struct dllredirect_data*)data.lpData;
ok_(__FILE__, line)(dlldata->size == data.ulLength, "got wrong size %d\n", dlldata->size);
ok_(__FILE__, line)(dlldata->unk == 2, "got wrong field value %d\n", dlldata->unk);
ok_(__FILE__, line)(dlldata->res[0] == 0, "got wrong res[0] value %d\n", dlldata->res[0]);
ok_(__FILE__, line)(dlldata->res[1] == 0, "got wrong res[1] value %d\n", dlldata->res[1]);
ok_(__FILE__, line)(dlldata->res[2] == 0, "got wrong res[2] value %d\n", dlldata->res[2]);
}
ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n");
ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n",
data.ulSectionGlobalDataLength);
ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n");
ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n",
data.ulSectionTotalLength);
ok_(__FILE__, line)(data.hActCtx == NULL, "data.hActCtx=%p\n", data.hActCtx);
ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n",
data.ulAssemblyRosterIndex, exid);
memset(&data, 0xfe, sizeof(data));
data.cbSize = sizeof(data);
ret = pFindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
libname, &data);
ok_(__FILE__, line)(ret, "FindActCtxSectionStringW failed: %u\n", GetLastError());
if (!ret) return;
ok_(__FILE__, line)(data.cbSize == sizeof(data), "data.cbSize=%u\n", data.cbSize);
ok_(__FILE__, line)(data.ulDataFormatVersion == 1, "data.ulDataFormatVersion=%u\n", data.ulDataFormatVersion);
ok_(__FILE__, line)(data.lpData != NULL, "data.lpData == NULL\n");
ok_(__FILE__, line)(data.ulLength == 20, "data.ulLength=%u\n", data.ulLength);
ok_(__FILE__, line)(data.lpSectionGlobalData == NULL, "data.lpSectionGlobalData != NULL\n");
ok_(__FILE__, line)(data.ulSectionGlobalDataLength == 0, "data.ulSectionGlobalDataLength=%u\n",
data.ulSectionGlobalDataLength);
ok_(__FILE__, line)(data.lpSectionBase != NULL, "data.lpSectionBase == NULL\n");
ok_(__FILE__, line)(data.ulSectionTotalLength > 0, "data.ulSectionTotalLength=%u\n",
data.ulSectionTotalLength);
ok_(__FILE__, line)(data.hActCtx == handle, "data.hActCtx=%p\n", data.hActCtx);
ok_(__FILE__, line)(data.ulAssemblyRosterIndex == exid, "data.ulAssemblyRosterIndex=%u, expected %u\n",
data.ulAssemblyRosterIndex, exid);
pReleaseActCtx(handle);
}
static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, int line) static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, int line)
{ {
struct wndclass_redirect_data *wnddata; struct wndclass_redirect_data *wnddata;
struct wndclass_header *header; struct strsection_header *header;
ACTCTX_SECTION_KEYED_DATA data; ACTCTX_SECTION_KEYED_DATA data;
BOOL ret; BOOL ret;
@ -885,7 +875,7 @@ static void test_find_window_class(HANDLE handle, LPCWSTR clsname, ULONG exid, i
wine_dbgstr_w(clsname)); wine_dbgstr_w(clsname));
if (!ret) return; if (!ret) return;
header = (struct wndclass_header*)data.lpSectionBase; header = (struct strsection_header*)data.lpSectionBase;
wnddata = (struct wndclass_redirect_data*)data.lpData; wnddata = (struct wndclass_redirect_data*)data.lpData;
ok_(__FILE__, line)(header->magic == 0x64487353, "got wrong magic 0x%08x\n", header->magic); ok_(__FILE__, line)(header->magic == 0x64487353, "got wrong magic 0x%08x\n", header->magic);
@ -1143,6 +1133,7 @@ static void test_wndclass_section(void)
static const WCHAR cls1W[] = {'1','.','2','.','3','.','4','!','w','n','d','C','l','a','s','s','1',0}; static const WCHAR cls1W[] = {'1','.','2','.','3','.','4','!','w','n','d','C','l','a','s','s','1',0};
ACTCTX_SECTION_KEYED_DATA data, data2; ACTCTX_SECTION_KEYED_DATA data, data2;
struct wndclass_redirect_data *classdata; struct wndclass_redirect_data *classdata;
struct strsection_header *section;
ULONG_PTR cookie; ULONG_PTR cookie;
HANDLE handle; HANDLE handle;
WCHAR *ptrW; WCHAR *ptrW;
@ -1176,6 +1167,10 @@ static void test_wndclass_section(void)
wndClass3W, &data2); wndClass3W, &data2);
ok(ret, "got %d\n", ret); ok(ret, "got %d\n", ret);
section = (struct strsection_header*)data.lpSectionBase;
ok(section->count == 4, "got %d\n", section->count);
ok(section->size == sizeof(*section), "got %d\n", section->size);
/* For both string same section is returned, meaning it's one wndclass section per context */ /* For both string same section is returned, meaning it's one wndclass section per context */
ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase); ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase);
ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength, ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength,
@ -1196,6 +1191,59 @@ static void test_wndclass_section(void)
pReleaseActCtx(handle); pReleaseActCtx(handle);
} }
static void test_dllredirect_section(void)
{
static const WCHAR testlib1W[] = {'t','e','s','t','l','i','b','1','.','d','l','l',0};
static const WCHAR testlib2W[] = {'t','e','s','t','l','i','b','2','.','d','l','l',0};
ACTCTX_SECTION_KEYED_DATA data, data2;
struct strsection_header *section;
ULONG_PTR cookie;
HANDLE handle;
BOOL ret;
/* use two dependent manifests, 4 'files' total */
create_manifest_file("testdep1.manifest", manifest_wndcls1, -1, NULL, NULL);
create_manifest_file("testdep2.manifest", manifest_wndcls2, -1, NULL, NULL);
create_manifest_file("main_wndcls.manifest", manifest_wndcls_main, -1, NULL, NULL);
handle = test_create("main_wndcls.manifest");
DeleteFileA("testdep1.manifest");
DeleteFileA("testdep2.manifest");
DeleteFileA("main_wndcls.manifest");
ret = pActivateActCtx(handle, &cookie);
ok(ret, "ActivateActCtx failed: %u\n", GetLastError());
memset(&data, 0, sizeof(data));
memset(&data2, 0, sizeof(data2));
data.cbSize = sizeof(data);
data2.cbSize = sizeof(data2);
/* get data for two files from different assemblies */
ret = pFindActCtxSectionStringW(0, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
testlib1W, &data);
ok(ret, "got %d\n", ret);
ret = pFindActCtxSectionStringW(0, NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
testlib2W, &data2);
ok(ret, "got %d\n", ret);
section = (struct strsection_header*)data.lpSectionBase;
ok(section->count == 4, "got %d\n", section->count);
ok(section->size == sizeof(*section), "got %d\n", section->size);
/* For both string same section is returned, meaning it's one dll redirect section per context */
ok(data.lpSectionBase == data2.lpSectionBase, "got %p, %p\n", data.lpSectionBase, data2.lpSectionBase);
ok(data.ulSectionTotalLength == data2.ulSectionTotalLength, "got %u, %u\n", data.ulSectionTotalLength,
data2.ulSectionTotalLength);
ret = pDeactivateActCtx(0, cookie);
ok(ret, "DeactivateActCtx failed: %u\n", GetLastError());
pReleaseActCtx(handle);
}
static void test_actctx(void) static void test_actctx(void)
{ {
ULONG_PTR cookie; ULONG_PTR cookie;
@ -1415,6 +1463,7 @@ static void test_actctx(void)
} }
test_wndclass_section(); test_wndclass_section();
test_dllredirect_section();
} }
static void test_app_manifest(void) static void test_app_manifest(void)

View File

@ -94,19 +94,20 @@ struct assembly_identity
BOOL optional; BOOL optional;
}; };
struct wndclass_header struct strsection_header
{ {
DWORD magic; DWORD magic;
DWORD unk1[4]; ULONG size;
DWORD unk1[3];
ULONG count; ULONG count;
ULONG index_offset; ULONG index_offset;
DWORD unk2[4]; DWORD unk2[4];
}; };
struct wndclass_index struct string_index
{ {
ULONG hash; /* original class name hash */ ULONG hash; /* key string hash */
ULONG name_offset; /* original class name offset */ ULONG name_offset;
ULONG name_len; ULONG name_len;
ULONG data_offset; /* redirect data offset */ ULONG data_offset; /* redirect data offset */
ULONG data_len; ULONG data_len;
@ -123,8 +124,24 @@ struct wndclass_redirect_data
ULONG module_offset;/* container name offset */ ULONG module_offset;/* container name offset */
}; };
struct dllredirect_data
{
ULONG size;
ULONG unk;
DWORD res[3];
};
/* /*
Window class redirection section is a plain buffer with following format:
Sections structure.
Sections are accessible by string or guid key, that defines two types of sections.
All sections of each type have same magic value and header structure, index
data could be of two possible types too. So every string based section uses
the same index format, same applies to guid sections - they share same guid index
format.
- window class redirection section is a plain buffer with following format:
<section header> <section header>
<index[]> <index[]>
@ -133,16 +150,25 @@ struct wndclass_redirect_data
<versioned name> <versioned name>
<module name> <module name>
Header is fixed length structure - struct wndclass_header, Header is fixed length structure - struct strsection_header,
contains redirected classes count; contains redirected classes count;
Index is an array of fixed length index records, each record is Index is an array of fixed length index records, each record is
struct wndclass_index. struct string_index.
All strings in data itself are WCHAR, null terminated, 4-bytes aligned. All strings in data itself are WCHAR, null terminated, 4-bytes aligned.
Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data), Versioned name offset is relative to redirect data structure (struct wndclass_redirect_data),
others are relative to section itself. others are relative to section itself.
- dll redirect section format:
<section header>
<index[]>
<data[]> --- <dll name>
<data>
This section doesn't seem to carry any payload data except dll names.
*/ */
struct entity struct entity
@ -218,7 +244,8 @@ struct assembly
enum context_sections enum context_sections
{ {
WINDOWCLASS_SECTION = 1 WINDOWCLASS_SECTION = 1,
DLLREDIRECT_SECTION = 2
}; };
typedef struct _ACTIVATION_CONTEXT typedef struct _ACTIVATION_CONTEXT
@ -232,7 +259,8 @@ typedef struct _ACTIVATION_CONTEXT
unsigned int allocated_assemblies; unsigned int allocated_assemblies;
/* section data */ /* section data */
DWORD sections; DWORD sections;
struct wndclass_header *wndclass_section; struct strsection_header *wndclass_section;
struct strsection_header *dllredirect_section;
} ACTIVATION_CONTEXT; } ACTIVATION_CONTEXT;
struct actctx_loader struct actctx_loader
@ -704,6 +732,7 @@ static void actctx_release( ACTIVATION_CONTEXT *actctx )
RtlFreeHeap( GetProcessHeap(), 0, actctx->config.info ); RtlFreeHeap( GetProcessHeap(), 0, actctx->config.info );
RtlFreeHeap( GetProcessHeap(), 0, actctx->appdir.info ); RtlFreeHeap( GetProcessHeap(), 0, actctx->appdir.info );
RtlFreeHeap( GetProcessHeap(), 0, actctx->assemblies ); RtlFreeHeap( GetProcessHeap(), 0, actctx->assemblies );
RtlFreeHeap( GetProcessHeap(), 0, actctx->dllredirect_section );
RtlFreeHeap( GetProcessHeap(), 0, actctx->wndclass_section ); RtlFreeHeap( GetProcessHeap(), 0, actctx->wndclass_section );
actctx->magic = 0; actctx->magic = 0;
RtlFreeHeap( GetProcessHeap(), 0, actctx ); RtlFreeHeap( GetProcessHeap(), 0, actctx );
@ -1415,6 +1444,9 @@ static BOOL parse_file_elem(xmlbuf_t* xmlbuf, struct assembly* assembly, struct
} }
if (error || !dll->name) return FALSE; if (error || !dll->name) return FALSE;
acl->actctx->sections |= DLLREDIRECT_SECTION;
if (end) return TRUE; if (end) return TRUE;
while (ret && (ret = next_xml_elem(xmlbuf, &elem))) while (ret && (ret = next_xml_elem(xmlbuf, &elem)))
@ -2208,26 +2240,43 @@ static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class )
return status; return status;
} }
static NTSTATUS fill_keyed_data(PACTCTX_SECTION_KEYED_DATA data, PVOID v1, PVOID v2, unsigned int i) static NTSTATUS build_dllredirect_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
{ {
data->ulDataFormatVersion = 1; unsigned int i, j, total_len = 0, dll_count = 0;
data->lpData = v1; struct strsection_header *header;
data->ulLength = 20; /* FIXME */ struct dllredirect_data *data;
data->lpSectionGlobalData = NULL; /* FIXME */ struct string_index *index;
data->ulSectionGlobalDataLength = 0; /* FIXME */ ULONG name_offset;
data->lpSectionBase = v2;
data->ulSectionTotalLength = 0; /* FIXME */
data->hActCtx = NULL;
if (data->cbSize >= offsetof(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
data->ulAssemblyRosterIndex = i + 1;
return STATUS_SUCCESS; /* 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];
static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *section_name, /* each entry needs index, data and string data */
PACTCTX_SECTION_KEYED_DATA data) total_len += sizeof(*index);
{ total_len += sizeof(*data);
unsigned int i, j, snlen = section_name->Length / sizeof(WCHAR); total_len += aligned_string_len((strlenW(dll->name)+1)*sizeof(WCHAR));
}
dll_count += assembly->num_dlls;
}
total_len += sizeof(*header);
header = RtlAllocateHeap(GetProcessHeap(), 0, total_len);
if (!header) return STATUS_NO_MEMORY;
memset(header, 0, sizeof(*header));
header->magic = SECTION_MAGIC;
header->size = sizeof(*header);
header->count = dll_count;
header->index_offset = sizeof(*header);
index = (struct string_index*)((BYTE*)header + header->index_offset);
name_offset = header->index_offset + header->count*sizeof(*index);
for (i = 0; i < actctx->num_assemblies; i++) for (i = 0; i < actctx->num_assemblies; i++)
{ {
@ -2235,34 +2284,132 @@ static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_S
for (j = 0; j < assembly->num_dlls; j++) for (j = 0; j < assembly->num_dlls; j++)
{ {
struct dll_redirect *dll = &assembly->dlls[j]; struct dll_redirect *dll = &assembly->dlls[j];
if (!strncmpiW(section_name->Buffer, dll->name, snlen) && !dll->name[snlen]) UNICODE_STRING str;
return fill_keyed_data(data, dll, assembly, i); WCHAR *ptrW;
/* setup new index entry */
str.Buffer = dll->name;
str.Length = strlenW(dll->name)*sizeof(WCHAR);
str.MaximumLength = str.Length + sizeof(WCHAR);
/* hash original class name */
RtlHashUnicodeString(&str, TRUE, HASH_STRING_ALGORITHM_X65599, &index->hash);
index->name_offset = name_offset;
index->name_len = str.Length;
index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
index->data_len = sizeof(*data);
index->rosterindex = i + 1;
/* setup data */
data = (struct dllredirect_data*)((BYTE*)header + index->data_offset);
data->size = sizeof(*data);
data->unk = 2; /* FIXME: seems to be constant */
memset(data->res, 0, sizeof(data->res));
/* dll name */
ptrW = (WCHAR*)((BYTE*)header + index->name_offset);
memcpy(ptrW, dll->name, index->name_len);
ptrW[index->name_len/sizeof(WCHAR)] = 0;
name_offset += sizeof(*data) + aligned_string_len(str.MaximumLength);
index++;
} }
} }
return STATUS_SXS_KEY_NOT_FOUND;
*section = header;
return STATUS_SUCCESS;
} }
static inline struct wndclass_index *get_wndclass_first_index(ACTIVATION_CONTEXT *actctx) static struct string_index *find_string_index(const struct strsection_header *section, const UNICODE_STRING *name)
{ {
return (struct wndclass_index*)((BYTE*)actctx->wndclass_section + actctx->wndclass_section->index_offset); struct string_index *iter, *index = NULL;
ULONG hash = 0, i;
RtlHashUnicodeString(name, TRUE, HASH_STRING_ALGORITHM_X65599, &hash);
iter = (struct string_index*)((BYTE*)section + section->index_offset);
for (i = 0; i < section->count; i++)
{
if (iter->hash == hash)
{
const WCHAR *nameW = (WCHAR*)((BYTE*)section + iter->name_offset);
if (!strcmpW(nameW, name->Buffer))
{
index = iter;
break;
}
else
WARN("hash collision 0x%08x, %s, %s\n", hash, debugstr_us(name), debugstr_w(nameW));
}
iter++;
}
return index;
} }
static inline struct wndclass_redirect_data *get_wndclass_data(ACTIVATION_CONTEXT *ctxt, struct wndclass_index *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);
}
static NTSTATUS find_dll_redirection(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
PACTCTX_SECTION_KEYED_DATA data)
{
struct dllredirect_data *dll;
struct string_index *index;
if (!(actctx->sections & DLLREDIRECT_SECTION)) return STATUS_SXS_KEY_NOT_FOUND;
if (!actctx->dllredirect_section)
{
struct strsection_header *section;
NTSTATUS status = build_dllredirect_section(actctx, &section);
if (status) return status;
if (interlocked_cmpxchg_ptr((void**)&actctx->dllredirect_section, section, NULL))
RtlFreeHeap(GetProcessHeap(), 0, section);
}
index = find_string_index(actctx->dllredirect_section, name);
if (!index) return STATUS_SXS_KEY_NOT_FOUND;
dll = get_dllredirect_data(actctx, index);
data->ulDataFormatVersion = 1;
data->lpData = dll;
data->ulLength = dll->size;
data->lpSectionGlobalData = NULL;
data->ulSectionGlobalDataLength = 0;
data->lpSectionBase = actctx->dllredirect_section;
data->ulSectionTotalLength = RtlSizeHeap( GetProcessHeap(), 0, actctx->dllredirect_section );
data->hActCtx = NULL;
if (data->cbSize >= FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) + sizeof(ULONG))
data->ulAssemblyRosterIndex = index->rosterindex;
return STATUS_SUCCESS;
}
static inline struct string_index *get_wndclass_first_index(ACTIVATION_CONTEXT *actctx)
{
return (struct string_index*)((BYTE*)actctx->wndclass_section + actctx->wndclass_section->index_offset);
}
static inline struct wndclass_redirect_data *get_wndclass_data(ACTIVATION_CONTEXT *ctxt, struct string_index *index)
{ {
return (struct wndclass_redirect_data*)((BYTE*)ctxt->wndclass_section + index->data_offset); return (struct wndclass_redirect_data*)((BYTE*)ctxt->wndclass_section + index->data_offset);
} }
static inline ULONG get_assembly_rosterindex(ACTIVATION_CONTEXT *actctx, const struct assembly* assembly) static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct strsection_header **section)
{
return (assembly - actctx->assemblies) + 1;
}
static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndclass_header **section)
{ {
unsigned int i, j, k, total_len = 0, class_count = 0; unsigned int i, j, k, total_len = 0, class_count = 0;
struct wndclass_redirect_data *data; struct wndclass_redirect_data *data;
struct wndclass_header *header; struct strsection_header *header;
struct wndclass_index *index; struct string_index *index;
ULONG name_offset; ULONG name_offset;
/* compute section length */ /* compute section length */
@ -2281,8 +2428,8 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
int len; int len;
/* each class entry needs index, data and string data */ /* each class entry needs index, data and string data */
total_len += sizeof(struct wndclass_index); total_len += sizeof(*index);
total_len += sizeof(struct wndclass_redirect_data); total_len += sizeof(*data);
/* original name is stored separately */ /* original name is stored separately */
total_len += aligned_string_len(class_len*sizeof(WCHAR)); total_len += aligned_string_len(class_len*sizeof(WCHAR));
/* versioned name and module name are stored one after another */ /* versioned name and module name are stored one after another */
@ -2306,9 +2453,10 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
memset(header, 0, sizeof(*header)); memset(header, 0, sizeof(*header));
header->magic = SECTION_MAGIC; header->magic = SECTION_MAGIC;
header->size = sizeof(*header);
header->count = class_count; header->count = class_count;
header->index_offset = sizeof(*header); header->index_offset = sizeof(*header);
index = (struct wndclass_index*)((BYTE*)header + header->index_offset); index = (struct string_index*)((BYTE*)header + header->index_offset);
name_offset = header->index_offset + header->count*sizeof(*index); name_offset = header->index_offset + header->count*sizeof(*index);
for (i = 0; i < actctx->num_assemblies; i++) for (i = 0; i < actctx->num_assemblies; i++)
@ -2345,7 +2493,7 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
index->name_len = str.Length; index->name_len = str.Length;
index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength); index->data_offset = index->name_offset + aligned_string_len(str.MaximumLength);
index->data_len = sizeof(*data) + versioned_len + module_len + 2*sizeof(WCHAR) /* two nulls */; index->data_len = sizeof(*data) + versioned_len + module_len + 2*sizeof(WCHAR) /* two nulls */;
index->rosterindex = get_assembly_rosterindex(actctx, assembly); index->rosterindex = i + 1;
/* setup data */ /* setup data */
data = (struct wndclass_redirect_data*)((BYTE*)header + index->data_offset); data = (struct wndclass_redirect_data*)((BYTE*)header + index->data_offset);
@ -2397,7 +2545,7 @@ static NTSTATUS build_wndclass_section(ACTIVATION_CONTEXT* actctx, struct wndcla
static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name, static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRING *name,
PACTCTX_SECTION_KEYED_DATA data) PACTCTX_SECTION_KEYED_DATA data)
{ {
struct wndclass_index *iter, *index = NULL; struct string_index *iter, *index = NULL;
struct wndclass_redirect_data *class; struct wndclass_redirect_data *class;
ULONG hash; ULONG hash;
int i; int i;
@ -2406,7 +2554,7 @@ static NTSTATUS find_window_class(ACTIVATION_CONTEXT* actctx, const UNICODE_STRI
if (!actctx->wndclass_section) if (!actctx->wndclass_section)
{ {
struct wndclass_header *section; struct strsection_header *section;
NTSTATUS status = build_wndclass_section(actctx, &section); NTSTATUS status = build_wndclass_section(actctx, &section);
if (status) return status; if (status) return status;