reactos/modules/rostests/apitests/kernel32/FindActCtxSectionStringW.c

335 lines
15 KiB
C
Raw Normal View History

/*
* Unit test suite for virtual substituted drive functions.
*
* Copyright 2017 Giannis Adamopoulos
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/
2017-12-13 12:48:26 +00:00
#include "precomp.h"
#define STRSECTION_MAGIC 0x64487353 /* dHsS */
struct strsection_header
{
DWORD magic;
ULONG size;
DWORD unk1[3];
ULONG count;
ULONG index_offset;
DWORD unk2[2];
ULONG global_offset;
ULONG global_len;
};
struct wndclass_redirect_data
{
ULONG size;
DWORD res;
ULONG name_len;
ULONG name_offset; /* versioned name offset */
ULONG module_len;
ULONG module_offset; /* container name offset to the section base */
};
struct dllredirect_data
{
ULONG size;
ULONG unk;
DWORD res[3];
};
#include <pshpack1.h>
struct assemply_data
{
ULONG size;
DWORD ulFlags;
DWORD ulEncodedAssemblyIdentityLength;
DWORD ulEncodedAssemblyIdentityOffset; /* offset to the section base */
DWORD ulManifestPathType;
DWORD ulManifestPathLength;
DWORD ulManifestPathOffset; /* offset to the section base */
LARGE_INTEGER liManifestLastWriteTime;
DWORD unk3[11];
DWORD ulAssemblyDirectoryNameLength;
DWORD ulAssemblyDirectoryNameOffset; /* offset to the section base */
DWORD unk4[3]; /* In win10 there are two more fields */
};
#include <poppack.h>
HANDLE _CreateActCtxFromFile(LPCWSTR FileName, int line)
{
ACTCTXW ActCtx = {sizeof(ACTCTX)};
HANDLE h;
WCHAR buffer[MAX_PATH] , *separator;
ok (GetModuleFileNameW(NULL, buffer, MAX_PATH), "GetModuleFileName failed\n");
separator = wcsrchr(buffer, L'\\');
if (separator)
wcscpy(separator + 1, FileName);
ActCtx.lpSource = buffer;
SetLastError(0xdeaddead);
h = CreateActCtxW(&ActCtx);
ok_(__FILE__, line)(h != INVALID_HANDLE_VALUE, "CreateActCtx failed for %S\n", FileName);
// In win10 last error is unchanged and in win2k3 it is ERROR_BAD_EXE_FORMAT
ok_(__FILE__, line)(GetLastError() == ERROR_BAD_EXE_FORMAT || GetLastError() == 0xdeaddead, "Wrong last error %lu\n", GetLastError());
return h;
}
VOID _ActivateCtx(HANDLE h, ULONG_PTR *cookie, int line)
{
BOOL res;
SetLastError(0xdeaddead);
res = ActivateActCtx(h, cookie);
ok_(__FILE__, line)(res == TRUE, "ActivateActCtx failed\n");
ok_(__FILE__, line)(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD)(0xdeaddead), GetLastError());
}
VOID _DeactivateCtx(ULONG_PTR cookie, int line)
{
BOOL res;
SetLastError(0xdeaddead);
res = DeactivateActCtx(0, cookie);
ok_(__FILE__, line)(res == TRUE, "DeactivateActCtx failed\n");
ok_(__FILE__, line)(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD)(0xdeaddead), GetLastError());
}
void TestClassRedirection(HANDLE h, LPCWSTR ClassToTest, LPCWSTR ExpectedClassPart, LPCWSTR ExpectedModule, ULONG ExpectedClassCount)
{
ACTCTX_SECTION_KEYED_DATA KeyedData = { 0 };
BOOL res;
struct strsection_header *header;
struct wndclass_redirect_data *classData;
LPCWSTR VersionedClass, ClassLib;
int data_lenght;
SetLastError(0xdeaddead);
KeyedData.cbSize = sizeof(KeyedData);
res = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
NULL,
ACTIVATION_CONTEXT_SECTION_WINDOW_CLASS_REDIRECTION,
ClassToTest,
&KeyedData);
ok(res == TRUE, "FindActCtxSectionString failed\n");
ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD)(0xdeaddead), GetLastError());
ok(KeyedData.ulDataFormatVersion == 1, "Wrong format version: %lu\n", KeyedData.ulDataFormatVersion);
ok(KeyedData.hActCtx == h, "Wrong handle\n");
ok(KeyedData.lpSectionBase != NULL, "Expected non null lpSectionBase\n");
ok(KeyedData.lpData != NULL, "Expected non null lpData\n");
header = (struct strsection_header*)KeyedData.lpSectionBase;
classData = (struct wndclass_redirect_data*)KeyedData.lpData;
if(res == FALSE || KeyedData.ulDataFormatVersion != 1 || header == NULL || classData == NULL)
{
skip("Can't read data for class. Skipping\n");
}
else
{
ok(header->magic == STRSECTION_MAGIC, "%lu\n", header->magic );
ok(header->size == sizeof(*header), "Got %lu instead of %d\n", header->size, sizeof(*header));
ok(header->count == ExpectedClassCount, "Expected %lu classes, got %lu\n", ExpectedClassCount, header->count );
VersionedClass = (WCHAR*)((BYTE*)classData + classData->name_offset);
ClassLib = (WCHAR*)((BYTE*)header + classData->module_offset);
data_lenght = classData->size + classData->name_len + classData->module_len + 2*sizeof(WCHAR);
ok(KeyedData.ulLength == data_lenght, "Got lenght %lu instead of %d\n", KeyedData.ulLength, data_lenght);
ok(classData->size == sizeof(*classData), "Got %lu instead of %d\n", classData->size, sizeof(*classData));
ok(classData->res == 0, "Got res %lu\n", classData->res);
ok(classData->module_len == wcslen(ExpectedModule) * 2, "Got name len %lu, expected %d\n", classData->module_len, wcslen(ExpectedModule) *2);
ok(wcscmp(ClassLib, ExpectedModule) == 0, "Got %S, expected %S\n", ClassLib, ExpectedModule);
/* compare only if VersionedClass starts with ExpectedClassPart */
ok(memcmp(VersionedClass, ExpectedClassPart, sizeof(WCHAR) * wcslen(ExpectedClassPart)) == 0, "Expected %S to start with %S\n", VersionedClass, ExpectedClassPart);
}
}
VOID TestLibDependency(HANDLE h)
{
ACTCTX_SECTION_KEYED_DATA KeyedData = { 0 };
BOOL res;
struct strsection_header *SectionHeader;
struct dllredirect_data *redirData;
struct assemply_data *assemplyData;
SetLastError(0xdeaddead);
KeyedData.cbSize = sizeof(KeyedData);
res = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
NULL,
ACTIVATION_CONTEXT_SECTION_DLL_REDIRECTION,
L"dep1.dll",
&KeyedData);
ok(res == TRUE, "FindActCtxSectionString failed\n");
ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD)(0xdeaddead), GetLastError());
ok(KeyedData.ulDataFormatVersion == 1, "Wrong format version: %lu", KeyedData.ulDataFormatVersion);
ok(KeyedData.hActCtx == h, "Wrong handle\n");
ok(KeyedData.lpSectionBase != NULL, "Expected non null lpSectionBase\n");
ok(KeyedData.lpData != NULL, "Expected non null lpData\n");
SectionHeader = (struct strsection_header*)KeyedData.lpSectionBase;
redirData = (struct dllredirect_data *)KeyedData.lpData;
if(res == FALSE || KeyedData.ulDataFormatVersion != 1 || SectionHeader == NULL || redirData == NULL)
{
skip("Can't read data for dep1.dll. Skipping\n");
}
else
{
ok(SectionHeader->magic == STRSECTION_MAGIC, "%lu\n", SectionHeader->magic );
ok(SectionHeader->size == sizeof(*SectionHeader), "Got %lu instead of %d\n", SectionHeader->size, sizeof(*SectionHeader));
ok(SectionHeader->count == 2, "%lu\n", SectionHeader->count ); /* 2 dlls? */
ok(redirData->size == sizeof(*redirData), "Got %lu instead of %d\n", redirData->size, sizeof(*redirData));
}
SetLastError(0xdeaddead);
KeyedData.cbSize = sizeof(KeyedData);
res = FindActCtxSectionStringW(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX,
NULL,
ACTIVATION_CONTEXT_SECTION_ASSEMBLY_INFORMATION,
L"dep1",
&KeyedData);
ok(res == TRUE, "FindActCtxSectionString failed\n");
ok(GetLastError() == 0xdeaddead, "Wrong last error. Expected %lu, got %lu\n", (DWORD)(0xdeaddead), GetLastError());
ok(KeyedData.ulDataFormatVersion == 1, "Wrong format version: %lu", KeyedData.ulDataFormatVersion);
ok(KeyedData.hActCtx == h, "Wrong handle\n");
ok(KeyedData.lpSectionBase != NULL, "Expected non null lpSectionBase\n");
ok(KeyedData.lpData != NULL, "Expected non null lpData\n");
SectionHeader = (struct strsection_header*)KeyedData.lpSectionBase;
assemplyData = (struct assemply_data*)KeyedData.lpData;;
if(res == FALSE || KeyedData.ulDataFormatVersion != 1 || SectionHeader == NULL || assemplyData == NULL)
{
skip("Can't read data for dep1. Skipping\n");
}
else
{
LPCWSTR AssemblyIdentity, ManifestPath, AssemblyDirectory;
int data_lenght;
DWORD buffer[256];
PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION details = (PACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION)buffer;
ok(SectionHeader->magic == STRSECTION_MAGIC, "%lu\n", SectionHeader->magic );
ok(SectionHeader->size == sizeof(*SectionHeader), "Got %lu instead of %d\n", SectionHeader->size, sizeof(*SectionHeader));
ok(SectionHeader->count == 2, "%lu\n", SectionHeader->count ); /* 2 dlls? */
data_lenght = assemplyData->size +
assemplyData->ulEncodedAssemblyIdentityLength +
assemplyData->ulManifestPathLength +
assemplyData->ulAssemblyDirectoryNameLength + 2 * sizeof(WCHAR);
ok(assemplyData->size == sizeof(*assemplyData), "Got %lu instead of %d\n", assemplyData->size, sizeof(*assemplyData));
ok(KeyedData.ulLength == data_lenght, "Got lenght %lu instead of %d\n", KeyedData.ulLength, data_lenght);
AssemblyIdentity = (WCHAR*)((BYTE*)SectionHeader + assemplyData->ulEncodedAssemblyIdentityOffset);
ManifestPath = (WCHAR*)((BYTE*)SectionHeader + assemplyData->ulManifestPathOffset);
AssemblyDirectory = (WCHAR*)((BYTE*)SectionHeader + assemplyData->ulAssemblyDirectoryNameOffset);
/* Use AssemblyDetailedInformationInActivationContext so as to infer the contents of assemplyData */
res = QueryActCtxW(0, h, &KeyedData.ulAssemblyRosterIndex,
AssemblyDetailedInformationInActivationContext,
&buffer, sizeof(buffer), NULL);
ok(res == TRUE, "QueryActCtxW failed\n");
ok(assemplyData->ulFlags == details->ulFlags, "\n");
ok(assemplyData->ulEncodedAssemblyIdentityLength == details->ulEncodedAssemblyIdentityLength, "\n");
ok(assemplyData->ulManifestPathType == details->ulManifestPathType, "\n");
ok(assemplyData->ulManifestPathLength == details->ulManifestPathLength, "\n");
ok(assemplyData->ulAssemblyDirectoryNameLength == details->ulAssemblyDirectoryNameLength, "\n");
ok(assemplyData->liManifestLastWriteTime.QuadPart == details->liManifestLastWriteTime.QuadPart, "\n");
ok(wcscmp(ManifestPath, details->lpAssemblyManifestPath) == 0, "Expected path %S, got %S\n", details->lpAssemblyManifestPath, ManifestPath);
ok(wcscmp(AssemblyDirectory, details->lpAssemblyDirectoryName) == 0, "Expected path %S, got %S\n", details->lpAssemblyManifestPath, ManifestPath);
/* It looks like that AssemblyIdentity isn't null terminated */
ok(memcmp(AssemblyIdentity, details->lpAssemblyEncodedAssemblyIdentity, assemplyData->ulEncodedAssemblyIdentityLength) == 0, "Got wrong AssemblyIdentity\n");
}
}
START_TEST(FindActCtxSectionStringW)
{
HANDLE h, h2;
ULONG_PTR cookie, cookie2;
/*First run the redirection tests without using our own actctx */
TestClassRedirection(NULL, L"Button", L"Button", L"comctl32.dll", 27);
/* Something activates an activation context that mentions comctl32 but comctl32 is not loaded */
ok( GetModuleHandleW(L"comctl32.dll") == NULL, "Expected comctl32 not to be loaded\n");
ok( GetModuleHandleW(L"user32.dll") == NULL, "Expected user32 not to be loaded\n");
/* Class redirection tests */
h = _CreateActCtxFromFile(L"classtest.manifest", __LINE__);
if (h != INVALID_HANDLE_VALUE)
{
_ActivateCtx(h, &cookie, __LINE__);
TestClassRedirection(h, L"Button", L"2.2.2.2!Button", L"testlib.dll", 5);
_ActivateCtx(NULL, &cookie2, __LINE__);
TestClassRedirection(NULL, L"Button", L"Button", L"comctl32.dll", 27);
_DeactivateCtx(cookie2, __LINE__);
_DeactivateCtx(cookie, __LINE__);
}
else
{
skip("Failed to create context for classtest.manifest\n");
}
/* Class redirection tests with multiple contexts in the activation stack */
h2 = _CreateActCtxFromFile(L"classtest2.manifest", __LINE__);
if (h != INVALID_HANDLE_VALUE && h2 != INVALID_HANDLE_VALUE)
{
_ActivateCtx(h, &cookie, __LINE__);
_ActivateCtx(h2, &cookie2, __LINE__);
TestClassRedirection(NULL, L"Button", L"Button", L"comctl32.dll", 27);
TestClassRedirection(h2, L"MyClass", L"1.1.1.1!MyClass", L"testlib.dll", 5);
_DeactivateCtx(cookie2, __LINE__);
TestClassRedirection(h, L"Button", L"2.2.2.2!Button", L"testlib.dll", 5);
_DeactivateCtx(cookie, __LINE__);
}
else
{
skip("Failed to create context for classtest.manifest\n");
}
/* Dependency tests */
h = _CreateActCtxFromFile(L"deptest.manifest", __LINE__);
if (h != INVALID_HANDLE_VALUE)
{
_ActivateCtx(h, &cookie, __LINE__);
TestLibDependency(h);
_DeactivateCtx(cookie, __LINE__);
}
else
{
skip("Failed to create context for deptest.manifest\n");
}
/* Activate a context that depends on comctl32 v6 and run class tests again */
h = _CreateActCtxFromFile(L"comctl32dep.manifest", __LINE__);
if (h != INVALID_HANDLE_VALUE)
{
_ActivateCtx(h, &cookie, __LINE__);
TestClassRedirection(h, L"Button", L"6.0.", L"comctl32.dll", 29);
ok( GetModuleHandleW(L"comctl32.dll") == NULL, "Expected comctl32 not to be loaded\n");
ok( GetModuleHandleW(L"user32.dll") == NULL, "Expected user32 not to be loaded\n");
_DeactivateCtx(cookie, __LINE__);
}
else
{
skip("Failed to create context for comctl32dep.manifest\n");
}
}