Signed-off-by: Fabian Maurer dark.shadow4@web.de --- v2 - Free dlls only once - fail when resource creation fails - better document activation context error on XP --- dlls/kernel32/tests/Makefile.in | 5 + dlls/kernel32/tests/resource.rc | 12 + dlls/kernel32/tests/sxs.c | 312 +++++++++++++++++++++++++ dlls/kernel32/tests/sxs_dll_1.c | 17 ++ dlls/kernel32/tests/sxs_dll_1.manifest | 7 + dlls/kernel32/tests/sxs_dll_1.spec | 1 + dlls/kernel32/tests/sxs_dll_2.c | 17 ++ dlls/kernel32/tests/sxs_dll_2.manifest | 7 + dlls/kernel32/tests/sxs_dll_2.spec | 1 + dlls/kernel32/tests/sxs_exe_1.manifest | 8 + dlls/kernel32/tests/sxs_exe_2.manifest | 8 + 11 files changed, 395 insertions(+) create mode 100644 dlls/kernel32/tests/sxs.c create mode 100644 dlls/kernel32/tests/sxs_dll_1.c create mode 100644 dlls/kernel32/tests/sxs_dll_1.manifest create mode 100644 dlls/kernel32/tests/sxs_dll_1.spec create mode 100644 dlls/kernel32/tests/sxs_dll_2.c create mode 100644 dlls/kernel32/tests/sxs_dll_2.manifest create mode 100644 dlls/kernel32/tests/sxs_dll_2.spec create mode 100644 dlls/kernel32/tests/sxs_exe_1.manifest create mode 100644 dlls/kernel32/tests/sxs_exe_2.manifest
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index e06141d9f6..0318cae322 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -29,6 +29,11 @@ SOURCES = \ profile.c \ resource.c \ resource.rc \ + sxs.c \ + sxs_dll_1.c \ + sxs_dll_1.spec \ + sxs_dll_2.c \ + sxs_dll_2.spec \ sync.c \ thread.c \ time.c \ diff --git a/dlls/kernel32/tests/resource.rc b/dlls/kernel32/tests/resource.rc index f40a87819e..1512a477aa 100644 --- a/dlls/kernel32/tests/resource.rc +++ b/dlls/kernel32/tests/resource.rc @@ -24,3 +24,15 @@ { MENUITEM "foo", 1 } + +/* @makedep: sxs_exe_1.manifest */ +sxs_exe_1.manifest RCDATA sxs_exe_1.manifest + +/* @makedep: sxs_exe_2.manifest */ +sxs_exe_2.manifest RCDATA sxs_exe_2.manifest + +/* @makedep: sxs_dll_1.manifest */ +sxs_dll_1.manifest RCDATA sxs_dll_1.manifest + +/* @makedep: sxs_dll_2.manifest */ +sxs_dll_2.manifest RCDATA sxs_dll_2.manifest diff --git a/dlls/kernel32/tests/sxs.c b/dlls/kernel32/tests/sxs.c new file mode 100644 index 0000000000..629e3c4991 --- /dev/null +++ b/dlls/kernel32/tests/sxs.c @@ -0,0 +1,312 @@ +/* + * Side by side tests + * + * Copyright 2019 Fabian Maurer + * + * 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 + */ + +#include "wine/test.h" +#include <winbase.h> +#include <windef.h> +#include "winuser.h" +#include <stdio.h> + +static BOOL write_resource_file(const char *path_tmp, const char *name_res, const char *name_file, char *path_file) +{ + HRSRC rsrc; + void *rsrc_data; + DWORD rsrc_size; + BOOL ret; + HANDLE hfile; + + rsrc = FindResourceA(GetModuleHandleA(NULL), name_res, (LPCSTR)RT_RCDATA); + if (!rsrc) + { + rsrc = FindResourceA(GetModuleHandleA(NULL), name_res, (LPCSTR)"TESTDLL"); + if (!rsrc) return FALSE; + } + + rsrc_data = LockResource(LoadResource(GetModuleHandleA(NULL), rsrc)); + if (!rsrc_data) return FALSE; + + rsrc_size = SizeofResource(GetModuleHandleA(NULL), rsrc); + if (!rsrc_size) return FALSE; + + sprintf(path_file, "%s%s", path_tmp, name_file); + hfile = CreateFileA(path_file, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + if (hfile == INVALID_HANDLE_VALUE) return FALSE; + + ret = WriteFile(hfile, rsrc_data, rsrc_size, &rsrc_size, NULL); + + CloseHandle(hfile); + return ret; +} + +static void get_application_directory(char *buffer, int buffer_size) +{ + char *end; + GetModuleFileNameA(NULL, buffer, buffer_size); + end = strrchr(buffer, '\'); + end[1] = 0; +} + +typedef struct +{ + char path_tmp[MAX_PATH]; + char path_dll[MAX_PATH]; + char path_manifest_exe[MAX_PATH]; + char path_manifest_dll[MAX_PATH]; + ACTCTXA context; + ULONG_PTR cookie; + HANDLE handle_context; + HMODULE module; + DWORD(WINAPI *test_func)(void); +} sxs_info; + +static BOOL fill_sxs_info(sxs_info *info, const char *temp, const char *path_dll, const char *exe_manifest, const char *dll_manifest) +{ + BOOL success; + + GetTempPathA(MAX_PATH, info->path_tmp); + strcat(info->path_tmp, temp); + strcat(info->path_tmp, "\"); + CreateDirectoryA(info->path_tmp, NULL); + + success = write_resource_file(info->path_tmp, path_dll, "sxs_dll.dll", info->path_dll); + ok(success, "Failed to create file for testing\n"); + if (!success) + return FALSE; + + success = write_resource_file(info->path_tmp, exe_manifest, exe_manifest, info->path_manifest_exe); + ok(success, "Failed to create file for testing\n"); + if (!success) + return FALSE; + + success = write_resource_file(info->path_tmp, dll_manifest, "sxs_dll.manifest", info->path_manifest_dll); + ok(success, "Failed to create file for testing\n"); + if (!success) + return FALSE; + + info->context.cbSize = sizeof(ACTCTXA); + info->context.lpSource = info->path_manifest_exe; + info->context.lpAssemblyDirectory = info->path_tmp; + info->context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + info->handle_context = CreateActCtxA(&info->context); + ok((info->handle_context != NULL && info->handle_context != INVALID_HANDLE_VALUE ) + || broken(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX), /* XP doesn't support manifests outside of PE files */ + "CreateActCtxA failed: %d\n", GetLastError()); + if (GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) + { + skip("Failed to create activation context.\n"); + return FALSE; + } + + success = ActivateActCtx(info->handle_context, &info->cookie); + ok(success, "ActivateActCtx failed: %d\n", GetLastError()); + + info->module = LoadLibraryA("sxs_dll.dll"); + ok(info->module != NULL, "LoadLibrary failed\n"); + + info->test_func = (void *)GetProcAddress(info->module, "test_func"); + ok(info->test_func != NULL, "GetProcAddress failed\n"); + + DeactivateActCtx(0, info->cookie); + return TRUE; +} + +static void clean_sxs_info(sxs_info *info) +{ + if (info->handle_context) + ReleaseActCtx(info->handle_context); + if (*info->path_dll) + ok(DeleteFileA(info->path_dll), "DeleteFileA failed for %s: %d\n", info->path_dll, GetLastError()); + if (*info->path_manifest_exe) + ok(DeleteFileA(info->path_manifest_exe), "DeleteFileA failed for %s: %d\n", info->path_manifest_exe, GetLastError()); + if (*info->path_manifest_dll) + ok(DeleteFileA(info->path_manifest_dll), "DeleteFileA failed for %s: %d\n", info->path_manifest_dll, GetLastError()); + if (*info->path_tmp) + ok(RemoveDirectoryA(info->path_tmp), "RemoveDirectoryA failed for %s: %d\n", info->path_tmp, GetLastError()); +} + +/* Test loading two sxs dlls at the same time */ +static void test_two_dlls_at_same_time(void) +{ + sxs_info dll_1 = {0}; + sxs_info dll_2 = {0}; + DWORD ret; + + if (!fill_sxs_info(&dll_1, "1", "sxs_dll_1.dll", "sxs_exe_1.manifest", "sxs_dll_1.manifest")) + goto cleanup; + if (!fill_sxs_info(&dll_2, "2", "sxs_dll_2.dll", "sxs_exe_2.manifest", "sxs_dll_2.manifest")) + goto cleanup; + + todo_wine + ok(dll_1.module != dll_2.module, "Libraries are the same\n"); + ret = dll_1.test_func(); + ok(ret == 1, "Got %d\n", ret); + ret = dll_2.test_func(); + todo_wine + ok(ret == 2, "Got %d\n", ret); + +cleanup: + if (dll_1.module) + FreeLibrary(dll_1.module); + if (dll_2.module) + FreeLibrary(dll_2.module); + clean_sxs_info(&dll_1); + clean_sxs_info(&dll_2); +} + +/* Test loading a normal dll and then a sxs dll with the same name */ +static void test_one_sxs_and_one_local_1(void) +{ + sxs_info dll = {0}; + char path_dll_local[MAX_PATH] = {0}; + char path_application[MAX_PATH]; + HMODULE module = NULL; + DWORD(WINAPI *test_func)(void); + DWORD ret; + + get_application_directory(path_application, sizeof(path_application)); + + ret = write_resource_file(path_application, "sxs_dll_2.dll", "sxs_dll.dll", path_dll_local); + ok(ret, "Failed to create file for testing\n"); + if (!ret) + goto cleanup; + + module = LoadLibraryA(path_dll_local); + test_func = (void *)GetProcAddress(module, "test_func"); + + if (!fill_sxs_info(&dll, "1", "sxs_dll_1.dll", "sxs_exe_1.manifest", "sxs_dll_1.manifest")) + goto cleanup; + + todo_wine + ok(dll.module != module, "Libraries are the same\n"); + ret = dll.test_func(); + todo_wine + ok(ret == 1, "Got %d\n", ret); + ret = test_func(); + ok(ret == 2, "Got %d\n", ret); + +cleanup: + if (module) + FreeLibrary(module); + if (dll.module) + FreeLibrary(dll.module); + if (*path_dll_local) + ok(DeleteFileA(path_dll_local), "DeleteFileA failed for %s: %d\n", path_dll_local, GetLastError()); + clean_sxs_info(&dll); +} + +/* Test if sxs dll has priority over normal dll */ +static void test_one_sxs_and_one_local_2(void) +{ + sxs_info dll = {0}; + char path_dll_local[MAX_PATH] = {0}; + char path_application[MAX_PATH]; + HMODULE module = NULL; + DWORD(WINAPI *test_func)(void); + DWORD ret; + + get_application_directory(path_application, sizeof(path_application)); + + ret = write_resource_file(path_application, "sxs_dll_2.dll", "sxs_dll.dll", path_dll_local); + ok (ret, "Failed to create file for testing\n"); + if (!ret) + goto cleanup; + + if (!fill_sxs_info(&dll, "1", "sxs_dll_1.dll", "sxs_exe_1.manifest", "sxs_dll_1.manifest")) + goto cleanup; + + module = LoadLibraryA(path_dll_local); + test_func = (void *)GetProcAddress(module, "test_func"); + + ok(dll.module != module, "Libraries are the same\n"); + ret = dll.test_func(); + ok(ret == 1, "Got %d\n", ret); + ret = test_func(); + ok(ret == 2, "Got %d\n", ret); + +cleanup: + if (module) + FreeLibrary(module); + if (dll.module) + FreeLibrary(dll.module); + if (*path_dll_local) + ok(DeleteFileA(path_dll_local), "DeleteFileA failed for %s: %d\n", path_dll_local, GetLastError()); + clean_sxs_info(&dll); +} + +static void run_sxs_test(int run) +{ + switch(run) + { + case 1: + test_two_dlls_at_same_time(); + break; + case 2: + test_one_sxs_and_one_local_1(); + break; + case 3: + test_one_sxs_and_one_local_2(); + break; + } +} + +static void run_child_process(int run) +{ + char cmdline[MAX_PATH]; + char exe[MAX_PATH]; + char **argv; + PROCESS_INFORMATION pi; + STARTUPINFOA si = { 0 }; + BOOL ret; + + winetest_get_mainargs( &argv ); + + if (strstr(argv[0], ".exe")) + sprintf(exe, "%s", argv[0]); + else + sprintf(exe, "%s.exe", argv[0]); + sprintf(cmdline, ""%s" %s %d", argv[0], argv[1], run); + + si.cb = sizeof(si); + ret = CreateProcessA(exe, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "Could not create process: %u\n", GetLastError()); + + winetest_wait_child_process( pi.hProcess ); + + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); +} + +START_TEST(sxs) +{ + int argc; + char **argv; + + argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + int run = atoi(argv[2]); + run_sxs_test(run); + return; + } + run_child_process(1); + run_child_process(2); + run_child_process(3); +} diff --git a/dlls/kernel32/tests/sxs_dll_1.c b/dlls/kernel32/tests/sxs_dll_1.c new file mode 100644 index 0000000000..908d235059 --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_1.c @@ -0,0 +1,17 @@ +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + break; + } + + return TRUE; +} + +DWORD WINAPI test_func(void) +{ + return 1; +} diff --git a/dlls/kernel32/tests/sxs_dll_1.manifest b/dlls/kernel32/tests/sxs_dll_1.manifest new file mode 100644 index 0000000000..61e3f4a652 --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_1.manifest @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0"> + <assemblyIdentity type="win32" name="sxs_dll" version="1.0.0.0" processorArchitecture="x86" publicKeyToken="0000000000000000"/> + <file name="sxs_dll.dll"> + <windowClass>sidebyside</windowClass> + </file> +</assembly> diff --git a/dlls/kernel32/tests/sxs_dll_1.spec b/dlls/kernel32/tests/sxs_dll_1.spec new file mode 100644 index 0000000000..ebbc584352 --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_1.spec @@ -0,0 +1 @@ +@ stdcall test_func() diff --git a/dlls/kernel32/tests/sxs_dll_2.c b/dlls/kernel32/tests/sxs_dll_2.c new file mode 100644 index 0000000000..262c53a484 --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_2.c @@ -0,0 +1,17 @@ +#include <windows.h> + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + switch (fdwReason) + { + case DLL_PROCESS_ATTACH: + break; + } + + return TRUE; +} + +DWORD WINAPI test_func(void) +{ + return 2; +} diff --git a/dlls/kernel32/tests/sxs_dll_2.manifest b/dlls/kernel32/tests/sxs_dll_2.manifest new file mode 100644 index 0000000000..37b39bea3b --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_2.manifest @@ -0,0 +1,7 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v3" manifestVersion="1.0"> + <assemblyIdentity type="win32" name="sxs_dll" version="2.0.0.0" processorArchitecture="x86" publicKeyToken="0000000000000000"/> + <file name="sxs_dll.dll"> + <windowClass>sidebyside</windowClass> + </file> +</assembly> diff --git a/dlls/kernel32/tests/sxs_dll_2.spec b/dlls/kernel32/tests/sxs_dll_2.spec new file mode 100644 index 0000000000..ebbc584352 --- /dev/null +++ b/dlls/kernel32/tests/sxs_dll_2.spec @@ -0,0 +1 @@ +@ stdcall test_func() diff --git a/dlls/kernel32/tests/sxs_exe_1.manifest b/dlls/kernel32/tests/sxs_exe_1.manifest new file mode 100644 index 0000000000..633374eca3 --- /dev/null +++ b/dlls/kernel32/tests/sxs_exe_1.manifest @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity type="win32" name="sxs_dll" version="1.0.0.0" processorArchitecture="x86" publicKeyToken="0000000000000000" language="*"/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/dlls/kernel32/tests/sxs_exe_2.manifest b/dlls/kernel32/tests/sxs_exe_2.manifest new file mode 100644 index 0000000000..f93e497124 --- /dev/null +++ b/dlls/kernel32/tests/sxs_exe_2.manifest @@ -0,0 +1,8 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity type="win32" name="sxs_dll" version="2.0.0.0" processorArchitecture="x86" publicKeyToken="0000000000000000" language="*"/> + </dependentAssembly> + </dependency> +</assembly> -- 2.21.0