Signed-off-by: Fabian Maurer dark.shadow4@web.de --- v3: Fix test on XP --- dlls/kernel32/tests/Makefile.in | 2 ++ dlls/kernel32/tests/actctx.c | 37 ++++++++++++++++++++++++++++++++- dlls/kernel32/tests/dummy.c | 0 dlls/kernel32/tests/dummy.spec | 0 dlls/ntdll/actctx.c | 3 ++- 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 dlls/kernel32/tests/dummy.c create mode 100644 dlls/kernel32/tests/dummy.spec
diff --git a/dlls/kernel32/tests/Makefile.in b/dlls/kernel32/tests/Makefile.in index 2f2ac5f8c3..ee0bbd2c8b 100644 --- a/dlls/kernel32/tests/Makefile.in +++ b/dlls/kernel32/tests/Makefile.in @@ -11,6 +11,8 @@ C_SRCS = \ debugger.c \ directory.c \ drive.c \ + dummy.c \ + dummy.spec \ environ.c \ fiber.c \ file.c \ diff --git a/dlls/kernel32/tests/actctx.c b/dlls/kernel32/tests/actctx.c index 96d9b8cbb6..5f1c33f162 100644 --- a/dlls/kernel32/tests/actctx.c +++ b/dlls/kernel32/tests/actctx.c @@ -2598,9 +2598,28 @@ static void delete_manifest_file(const char *filename) DeleteFileA(path); }
+/* Copied from msi tests */ +static void extract_resource(const char *name, const char *type, const char *path) +{ + DWORD written; + HANDLE file; + HRSRC res; + void *ptr; + + file = CreateFileA(path, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, 0); + ok(file != INVALID_HANDLE_VALUE, "file creation failed, at %s, error %d\n", path, GetLastError()); + + res = FindResourceA(NULL, name, type); + ok( res != 0, "couldn't find resource\n" ); + ptr = LockResource( LoadResource( GetModuleHandleA(NULL), res )); + WriteFile( file, ptr, SizeofResource( GetModuleHandleA(NULL), res ), &written, NULL ); + ok( written == SizeofResource( GetModuleHandleA(NULL), res ), "couldn't write resource\n" ); + CloseHandle( file ); +} + static void test_CreateActCtx(void) { - CHAR path[MAX_PATH], dir[MAX_PATH]; + CHAR path[MAX_PATH], dir[MAX_PATH], dll[MAX_PATH]; ACTCTXA actctx; HANDLE handle;
@@ -2637,6 +2656,22 @@ todo_wine { } if (handle != INVALID_HANDLE_VALUE) pReleaseActCtx(handle);
+ /* with specified directory, that does contain dependent assembly */ + GetTempPathA(ARRAY_SIZE(dir), dir); + actctx.lpAssemblyDirectory = dir; + handle = pCreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE, "got handle %p\n", handle); + pReleaseActCtx(handle); + + /* Should still work if we add a dll with the same name, but without manifest */ + strcpy(dll, dir); + strcat(dll, "testdep1.dll"); + extract_resource("dummy.dll", "TESTDLL", dll); + handle = pCreateActCtxA(&actctx); + ok(handle != INVALID_HANDLE_VALUE || broken(GetLastError() == ERROR_SXS_CANT_GEN_ACTCTX) , "got error %d\n", GetLastError()); + pReleaseActCtx(handle); + DeleteFileA(dll); + delete_manifest_file("main_wndcls.manifest"); delete_manifest_file("testdep1.manifest"); delete_manifest_file("testdep2.manifest"); diff --git a/dlls/kernel32/tests/dummy.c b/dlls/kernel32/tests/dummy.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dlls/kernel32/tests/dummy.spec b/dlls/kernel32/tests/dummy.spec new file mode 100644 index 0000000000..e69de29bb2 diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 53a8b06882..08b6c509ae 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -3294,7 +3294,8 @@ static NTSTATUS lookup_assembly(struct actctx_loader* acl, status = get_manifest_in_pe_file( acl, ai, nameW.Buffer, directory, FALSE, file, (LPCWSTR)CREATEPROCESS_MANIFEST_RESOURCE_ID, 0 ); NtClose( file ); - break; + if (status == STATUS_SUCCESS) + break; } RtlFreeUnicodeString( &nameW ); }
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de --- v2: Release COM objects Turn skips into errors Remove unused run number --- dlls/mscoree/tests/Makefile.in | 4 + dlls/mscoree/tests/comtest.c | 300 ++++++++++++++++++++++++ dlls/mscoree/tests/comtest.cs | 23 ++ dlls/mscoree/tests/comtest_dll.manifest | 16 ++ dlls/mscoree/tests/comtest_exe.manifest | 11 + dlls/mscoree/tests/interfaces.idl | 33 +++ dlls/mscoree/tests/resource.rc | 30 +++ 7 files changed, 417 insertions(+) create mode 100644 dlls/mscoree/tests/comtest.c create mode 100644 dlls/mscoree/tests/comtest.cs create mode 100644 dlls/mscoree/tests/comtest_dll.manifest create mode 100644 dlls/mscoree/tests/comtest_exe.manifest create mode 100644 dlls/mscoree/tests/interfaces.idl create mode 100644 dlls/mscoree/tests/resource.rc
diff --git a/dlls/mscoree/tests/Makefile.in b/dlls/mscoree/tests/Makefile.in index 7c1ba5cb11..9e53b7c577 100644 --- a/dlls/mscoree/tests/Makefile.in +++ b/dlls/mscoree/tests/Makefile.in @@ -2,6 +2,10 @@ TESTDLL = mscoree.dll IMPORTS = ole32 shlwapi uuid
C_SRCS = \ + comtest.c \ debugging.c \ metahost.c \ mscoree.c + +RC_SRCS = resource.rc +IDL_SRCS = interfaces.idl diff --git a/dlls/mscoree/tests/comtest.c b/dlls/mscoree/tests/comtest.c new file mode 100644 index 0000000000..c8af630d7b --- /dev/null +++ b/dlls/mscoree/tests/comtest.c @@ -0,0 +1,300 @@ +/* + * Copyright 2018 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 + */ + +#define COBJMACROS +#include <stdio.h> + +#include "windows.h" +#include "ole2.h" +#include "mscoree.h" +#include "corerror.h" +#include "shlwapi.h" + +#include "wine/test.h" + +#include "initguid.h" +#include "interfaces.h" + +HMODULE hmscoree; + +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) 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; + + strcpy(path_file, path_tmp); + PathAppendA(path_file, 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; +} + +typedef HRESULT (WINAPI *_DllGetClassObject)(REFCLSID rclsid, REFIID riid, LPVOID *ppv); + +static void run_test(void) +{ + ITest *test = NULL; + HRESULT hr; + _DllGetClassObject getClassObject; + IClassFactory *classFactory = NULL; + + hr = CoCreateInstance(&CLSID_Test, NULL, CLSCTX_INPROC_SERVER, &IID_ITest, (void**)&test); + todo_wine + ok(hr == S_OK, "Got %x\n", hr); + + if (test) + { + int i = 0; + hr = ITest_Func(test, &i); + ok(hr == S_OK, "Got %x\n", hr); + ok(i == 42, "Expected 42, got %d\n", i); + ITest_Release(test); + } + + getClassObject = (_DllGetClassObject)GetProcAddress(hmscoree, "DllGetClassObject"); + hr = getClassObject(&CLSID_Test, &IID_IClassFactory, (void **)&classFactory); + ok(hr == S_OK, "Got %x\n", hr); + + if (classFactory) + { + ITest *test2 = NULL; + hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2); + todo_wine + ok(hr == S_OK, "Got %x\n", hr); + + if (test2) + { + int i = 0; + hr = ITest_Func(test2, &i); + ok(hr == S_OK, "Got %x\n", hr); + ok(i == 42, "Expected 42, got %d\n", i); + ITest_Release(test2); + } + IClassFactory_Release(classFactory); + } +} + +static BOOL compile_cs_to_dll(char *source_path, char *dest_path) +{ + const char *path_csc = "C:\windows\Microsoft.NET\Framework\v2.0.50727\csc.exe"; + char cmdline[MAX_PATH]; + PROCESS_INFORMATION pi; + STARTUPINFOA si = { 0 }; + BOOL ret; + + if (!PathFileExistsA(path_csc)) + { + skip("Can't find csc.exe\n"); + return FALSE; + } + + sprintf(cmdline, "%s /t:library /out:"%s" "%s"", path_csc, dest_path, source_path); + + si.cb = sizeof(si); + ret = CreateProcessA(path_csc, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi); + ok(ret, "Could not create process: %u\n", GetLastError()); + + WaitForSingleObject(pi.hProcess, 5000); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); + + ret = PathFileExistsA(dest_path); + ok(ret, "Compilation failed\n"); + return ret; +} + +static void prepare_and_run_test(const char *dll_source) +{ + char path_tmp[MAX_PATH] = {0}; + char path_dll[MAX_PATH] = {0}; + char path_dll_source[MAX_PATH] = {0}; + char path_current[MAX_PATH] = {0}; + char path_manifest_dll[MAX_PATH] = {0}; + char path_manifest_exe[MAX_PATH] = {0}; + BOOL success; + ACTCTXA context = {0}; + ULONG_PTR cookie; + HANDLE handle_context = 0; + + GetCurrentDirectoryA(MAX_PATH, path_current); + GetTempPathA(MAX_PATH, path_tmp); + + if (!write_resource_file(path_tmp, dll_source, "comtest.cs", path_dll_source)) + { + ok(0, "Failed to create file for testing\n"); + goto cleanup; + } + + strcpy(path_dll, path_current); + PathAppendA(path_dll, "comtest.dll"); + + if (!compile_cs_to_dll(path_dll_source, path_dll)) + goto cleanup; + + if (!write_resource_file(path_tmp, "comtest_exe.manifest", "exe.manifest", path_manifest_exe)) + { + ok(0, "Failed to create file for testing\n"); + goto cleanup; + } + + if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll)) + { + ok(0, "Failed to create file for testing\n"); + goto cleanup; + } + + context.cbSize = sizeof(ACTCTXA); + context.lpSource = path_manifest_exe; + context.lpAssemblyDirectory = path_tmp; + context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + handle_context = CreateActCtxA(&context); + ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "CreateActCtxA failed: %d\n", GetLastError()); + + if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE) + { + ok(0, "Failed to create activation context\n"); + goto cleanup; + } + + success = ActivateActCtx(handle_context, &cookie); + ok(success, "ActivateActCtx failed: %d\n", GetLastError()); + + run_test(); + +cleanup: + if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE) + { + success = DeactivateActCtx(0, cookie); + ok(success, "DeactivateActCtx failed: %d\n", GetLastError()); + ReleaseActCtx(handle_context); + } + if (*path_manifest_exe) + { + success = DeleteFileA(path_manifest_exe); + ok(success, "DeleteFileA failed: %d\n", GetLastError()); + } + if(*path_manifest_dll) + { + success = DeleteFileA(path_manifest_dll); + ok(success, "DeleteFileA failed: %d\n", GetLastError()); + } + if(*path_dll_source) + { + success = DeleteFileA(path_dll_source); + ok(success, "DeleteFileA failed: %d\n", GetLastError()); + } + /* dll cleanup is handled by the parent, because it might still be used by the child */ +} + + +static void cleanup_test(void) +{ + char path_dll[MAX_PATH] = {0}; + BOOL success; + + GetCurrentDirectoryA(MAX_PATH, path_dll); + PathAppendA(path_dll, "comtest.dll"); + + if (!PathFileExistsA(path_dll)) + return; + + success = DeleteFileA(path_dll); + if (!success) + { + Sleep(500); + success = DeleteFileA(path_dll); + } + ok(success, "DeleteFileA failed: %d\n", GetLastError()); +} + +static void run_child_process(const char *dll_source) +{ + 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 %s", argv[0], argv[1], dll_source); + + 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); + + /* Cleanup dll, because it might still have been used by the child */ + cleanup_test(); +} + +START_TEST(comtest) +{ + int argc; + char **argv; + + CoInitialize(NULL); + + hmscoree = LoadLibraryA("mscoree.dll"); + if (!hmscoree) + { + skip(".NET or mono not available\n"); + return; + } + + argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + const char *dll_source = argv[2]; + prepare_and_run_test(dll_source); + + goto cleanup; + } + + run_child_process("comtest.cs"); + +cleanup: + FreeLibrary(hmscoree); + CoUninitialize(); +} diff --git a/dlls/mscoree/tests/comtest.cs b/dlls/mscoree/tests/comtest.cs new file mode 100644 index 0000000000..4fe2a718b2 --- /dev/null +++ b/dlls/mscoree/tests/comtest.cs @@ -0,0 +1,23 @@ +/* Compile with + csc /target:library /out:dll.dll comtest.cs +*/ + +using System.Runtime.InteropServices; + +namespace DLL +{ + [Guid("1dbc4491-080d-45c5-a15d-1e3c4610bdd9"), ComVisible(true), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + public interface ITest + { + void Func(ref int i); + } + + [Guid("2e106e50-e7a4-4489-8538-83643f100fdc"), ComVisible(true), ClassInterface(ClassInterfaceType.None)] + public class Test : ITest + { + public void Func(ref int i) + { + i = 42; + } + } +} diff --git a/dlls/mscoree/tests/comtest_dll.manifest b/dlls/mscoree/tests/comtest_dll.manifest new file mode 100644 index 0000000000..ef6924de9e --- /dev/null +++ b/dlls/mscoree/tests/comtest_dll.manifest @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity + name="comtest" + version="1.0.0.0" + type="win32" + /> + <clrClass + clsid="{2e106e50-e7a4-4489-8538-83643f100fdc}" + threadingModel="Both" + name="DLL.Test" + runtimeVersion="v4.0.0.0"> + </clrClass> + <file name="comtest.dll"> + </file> +</assembly> diff --git a/dlls/mscoree/tests/comtest_exe.manifest b/dlls/mscoree/tests/comtest_exe.manifest new file mode 100644 index 0000000000..bc9ce4c045 --- /dev/null +++ b/dlls/mscoree/tests/comtest_exe.manifest @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity + name="comtest" + version="1.0.0.0" + type="win32"/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/dlls/mscoree/tests/interfaces.idl b/dlls/mscoree/tests/interfaces.idl new file mode 100644 index 0000000000..9e64988197 --- /dev/null +++ b/dlls/mscoree/tests/interfaces.idl @@ -0,0 +1,33 @@ +/* + * Copyright 2018 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 "unknwn.idl" + +[ + object, + uuid(1dbc4491-080d-45c5-a15d-1e3c4610bdd9), + local +] +interface ITest : IUnknown { + HRESULT Func([in, out] int *i); +}; + +[ + uuid(2e106e50-e7a4-4489-8538-83643f100fdc), +] +coclass Test { interface ITest; }; diff --git a/dlls/mscoree/tests/resource.rc b/dlls/mscoree/tests/resource.rc new file mode 100644 index 0000000000..9a1b89f656 --- /dev/null +++ b/dlls/mscoree/tests/resource.rc @@ -0,0 +1,30 @@ +/* + * Resources for mscoree test suite. + * + * Copyright 2018 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 "windef.h" + +/* @makedep: comtest.cs */ +comtest.cs RCDATA comtest.cs + +/* @makedep: comtest_exe.manifest */ +comtest_exe.manifest RCDATA comtest_exe.manifest + +/* @makedep: comtest_dll.manifest */ +comtest_dll.manifest RCDATA comtest_dll.manifest
In run_test, I would check the hr instead of the returned pointer. If we get S_OK, we should get a non-null interface pointer.
Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/mscoree/corruntimehost.c | 218 ++++++++++++++++++++++++---------- dlls/mscoree/tests/comtest.c | 2 - 2 files changed, 157 insertions(+), 63 deletions(-)
diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c index 5c4e7f1d6e..a63a9eb338 100644 --- a/dlls/mscoree/corruntimehost.c +++ b/dlls/mscoree/corruntimehost.c @@ -29,6 +29,7 @@ #include "winreg.h" #include "ole2.h" #include "shellapi.h" +#include "shlwapi.h"
#include "cor.h" #include "mscoree.h" @@ -40,6 +41,7 @@
#include "wine/debug.h" #include "wine/unicode.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL( mscoree );
@@ -68,6 +70,43 @@ struct dll_fixup void *tokens; /* pointer into process heap */ };
+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; + ULONG clrdata_len; + ULONG clrdata_offset; + DWORD miscstatus; + DWORD miscstatuscontent; + DWORD miscstatusthumbnail; + DWORD miscstatusicon; + DWORD miscstatusdocprint; +}; + +struct clrclass_data +{ + ULONG size; + DWORD res[2]; + ULONG module_len; + ULONG module_offset; + ULONG name_len; + ULONG name_offset; + ULONG version_len; + ULONG version_offset; + DWORD res2[2]; +}; + static MonoDomain* domain_attach(MonoDomain *domain) { MonoDomain *prev_domain = mono_domain_get(); @@ -1606,6 +1645,56 @@ HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, return CLASS_E_CLASSNOTAVAILABLE; }
+static BOOL try_create_registration_free_com(REFIID clsid, WCHAR *classname, WCHAR *filename) +{ + ACTCTX_SECTION_KEYED_DATA guid_info = { sizeof(ACTCTX_SECTION_KEYED_DATA) }; + ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *assembly_info; + SIZE_T bytes_assembly_info; + struct comclassredirect_data *redirect_data; + struct clrclass_data *class_data; + void *ptr_name; + const WCHAR *ptr_path_start, *ptr_path_end; + WCHAR path[MAX_PATH] = {0}; + WCHAR str_dll[] = {'.','d','l','l',0}; + + if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, clsid, &guid_info)) + { + DWORD error = GetLastError(); + if (error != ERROR_SXS_KEY_NOT_FOUND) + ERR("Failed to find guid: %d\n", error); + return FALSE; + } + + QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, AssemblyDetailedInformationInActivationContext, NULL, 0, &bytes_assembly_info); + assembly_info = heap_alloc(bytes_assembly_info); + if (!QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, + AssemblyDetailedInformationInActivationContext, assembly_info, bytes_assembly_info, &bytes_assembly_info)) + { + ERR("QueryActCtxW failed: %d!\n", GetLastError()); + heap_free(assembly_info); + ReleaseActCtx(guid_info.hActCtx); + return FALSE; + } + + redirect_data = guid_info.lpData; + class_data = (void *)((char*)redirect_data + redirect_data->clrdata_offset); + + ptr_name = (char *)class_data + class_data->name_offset; + strcpyW(classname, ptr_name); + + ptr_path_start = assembly_info->lpAssemblyEncodedAssemblyIdentity; + ptr_path_end = strchrW(ptr_path_start, ','); + memcpy(path, ptr_path_start, (char*)ptr_path_end - (char*)ptr_path_start); + + GetCurrentDirectoryW(MAX_PATH, filename); + PathAppendW(filename, path); + strcatW(filename, str_dll); + + heap_free(assembly_info); + ReleaseActCtx(guid_info.hActCtx); + return TRUE; +} + #define CHARS_IN_GUID 39
HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) @@ -1640,75 +1729,82 @@ HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) TRACE("Registry key: %s\n", debugstr_w(path));
res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key); - if (res == ERROR_FILE_NOT_FOUND) - return CLASS_E_CLASSNOTAVAILABLE; - - res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); - if(res != ERROR_SUCCESS) + if (res != ERROR_FILE_NOT_FOUND) { - WARN("Class value cannot be found.\n"); - hr = CLASS_E_CLASSNOTAVAILABLE; - goto cleanup; - } + res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); + if(res != ERROR_SUCCESS) + { + WARN("Class value cannot be found.\n"); + hr = CLASS_E_CLASSNOTAVAILABLE; + goto cleanup; + }
- TRACE("classname (%s)\n", debugstr_w(classname)); + TRACE("classname (%s)\n", debugstr_w(classname));
- dwBufLen = MAX_PATH + 8; - res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); - if(res == ERROR_SUCCESS) - { - /* Strip file:/// */ - if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) - offset = strlenW(wszFileSlash); + dwBufLen = MAX_PATH + 8; + res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); + if(res == ERROR_SUCCESS) + { + /* Strip file:/// */ + if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) + offset = strlenW(wszFileSlash); + + strcpyW(filename, codebase + offset); + } + else + { + WCHAR assemblyname[MAX_PATH + 8];
- strcpyW(filename, codebase + offset); + hr = CLASS_E_CLASSNOTAVAILABLE; + WARN("CodeBase value cannot be found, trying Assembly.\n"); + /* get the last subkey of InprocServer32 */ + res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0); + if (res != ERROR_SUCCESS || numKeys == 0) + goto cleanup; + numKeys--; + keyLength = ARRAY_SIZE(subkeyName); + res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0); + if (res != ERROR_SUCCESS) + goto cleanup; + res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey); + if (res != ERROR_SUCCESS) + goto cleanup; + dwBufLen = MAX_PATH + 8; + res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen); + RegCloseKey(subkey); + if (res != ERROR_SUCCESS) + goto cleanup; + + hr = get_file_from_strongname(assemblyname, filename, MAX_PATH); + if (FAILED(hr)) + { + /* + * The registry doesn't have a CodeBase entry and it's not in the GAC. + * + * Use the Assembly Key to retrieve the filename. + * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null + */ + WCHAR *ns; + + WARN("Attempt to load from the application directory.\n"); + GetModuleFileNameW(NULL, filename, MAX_PATH); + ns = strrchrW(filename, '\'); + *(ns+1) = '\0'; + + ns = strchrW(assemblyname, ','); + *(ns) = '\0'; + strcatW(filename, assemblyname); + *(ns) = '.'; + strcatW(filename, wszDLL); + } + } } else { - WCHAR assemblyname[MAX_PATH + 8]; - - hr = CLASS_E_CLASSNOTAVAILABLE; - WARN("CodeBase value cannot be found, trying Assembly.\n"); - /* get the last subkey of InprocServer32 */ - res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0); - if (res != ERROR_SUCCESS || numKeys == 0) - goto cleanup; - numKeys--; - keyLength = ARRAY_SIZE(subkeyName); - res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0); - if (res != ERROR_SUCCESS) - goto cleanup; - res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey); - if (res != ERROR_SUCCESS) - goto cleanup; - dwBufLen = MAX_PATH + 8; - res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen); - RegCloseKey(subkey); - if (res != ERROR_SUCCESS) - goto cleanup; + if (!try_create_registration_free_com(riid, classname, filename)) + return CLASS_E_CLASSNOTAVAILABLE;
- hr = get_file_from_strongname(assemblyname, filename, MAX_PATH); - if (FAILED(hr)) - { - /* - * The registry doesn't have a CodeBase entry and it's not in the GAC. - * - * Use the Assembly Key to retrieve the filename. - * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null - */ - WCHAR *ns; - - WARN("Attempt to load from the application directory.\n"); - GetModuleFileNameW(NULL, filename, MAX_PATH); - ns = strrchrW(filename, '\'); - *(ns+1) = '\0'; - - ns = strchrW(assemblyname, ','); - *(ns) = '\0'; - strcatW(filename, assemblyname); - *(ns) = '.'; - strcatW(filename, wszDLL); - } + TRACE("classname (%s)\n", debugstr_w(classname)); }
TRACE("filename (%s)\n", debugstr_w(filename)); diff --git a/dlls/mscoree/tests/comtest.c b/dlls/mscoree/tests/comtest.c index c8af630d7b..60bc2d5b1a 100644 --- a/dlls/mscoree/tests/comtest.c +++ b/dlls/mscoree/tests/comtest.c @@ -70,7 +70,6 @@ static void run_test(void) IClassFactory *classFactory = NULL;
hr = CoCreateInstance(&CLSID_Test, NULL, CLSCTX_INPROC_SERVER, &IID_ITest, (void**)&test); - todo_wine ok(hr == S_OK, "Got %x\n", hr);
if (test) @@ -90,7 +89,6 @@ static void run_test(void) { ITest *test2 = NULL; hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2); - todo_wine ok(hr == S_OK, "Got %x\n", hr);
if (test2)
How long can classname be? Do we need a size check when copying it?
I don't think we can assume the assembly dll is in the working directory.
How long can classname be? Do we need a size check when copying it?
I don't think they can be longer than the names of non-registration free classes.
I don't think we can assume the assembly dll is in the working directory.
I tried putting it into the folder the manifest points to, but windows can't seem to find it unless it's in the working directory. Feel free to prove me wrong though.
Regards, Fabian Maurer
I don't think we can assume the assembly dll is in the working directory.
I tried putting it into the folder the manifest points to, but windows can't seem to find it unless it's in the working directory. Feel free to prove me wrong though.
It's more likely the .exe directory than the working directory.
The normal dll path is also a reasonable place to search. It probably wouldn't use the GAC because that requires an install.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/mscoree/corruntimehost.c.rej | 145 ++++++++++++++++++ dlls/sxs/sxs.c | 148 ++++++++++++++++++ dlls/sxs/sxs.spec | 1 + dlls/sxs/tests/Makefile.in | 8 +- dlls/sxs/tests/comtest_dll.manifest | 16 ++ dlls/sxs/tests/comtest_exe.manifest | 11 ++ dlls/sxs/tests/interfaces.idl | 33 ++++ dlls/sxs/tests/resource.rc | 27 ++++ dlls/sxs/tests/sxs.c | 223 ++++++++++++++++++++++++++++ 9 files changed, 610 insertions(+), 2 deletions(-) create mode 100644 dlls/mscoree/corruntimehost.c.rej create mode 100644 dlls/sxs/tests/comtest_dll.manifest create mode 100644 dlls/sxs/tests/comtest_exe.manifest create mode 100644 dlls/sxs/tests/interfaces.idl create mode 100644 dlls/sxs/tests/resource.rc create mode 100644 dlls/sxs/tests/sxs.c
diff --git a/dlls/mscoree/corruntimehost.c.rej b/dlls/mscoree/corruntimehost.c.rej new file mode 100644 index 0000000000..20959fd1f4 --- /dev/null +++ b/dlls/mscoree/corruntimehost.c.rej @@ -0,0 +1,145 @@ +diff a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c (rejected hunks) +@@ -1640,75 +1729,82 @@ HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) + TRACE("Registry key: %s\n", debugstr_w(path)); + + res = RegOpenKeyExW(HKEY_CLASSES_ROOT, path, 0, KEY_READ, &key); +- if (res == ERROR_FILE_NOT_FOUND) +- return CLASS_E_CLASSNOTAVAILABLE; +- +- res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); +- if(res != ERROR_SUCCESS) ++ if (res != ERROR_FILE_NOT_FOUND) + { +- WARN("Class value cannot be found.\n"); +- hr = CLASS_E_CLASSNOTAVAILABLE; +- goto cleanup; +- } ++ res = RegGetValueW( key, NULL, wszClass, RRF_RT_REG_SZ, NULL, classname, &dwBufLen); ++ if(res != ERROR_SUCCESS) ++ { ++ WARN("Class value cannot be found.\n"); ++ hr = CLASS_E_CLASSNOTAVAILABLE; ++ goto cleanup; ++ } + +- TRACE("classname (%s)\n", debugstr_w(classname)); ++ TRACE("classname (%s)\n", debugstr_w(classname)); + +- dwBufLen = MAX_PATH + 8; +- res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); +- if(res == ERROR_SUCCESS) +- { +- /* Strip file:/// */ +- if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) +- offset = strlenW(wszFileSlash); ++ dwBufLen = MAX_PATH + 8; ++ res = RegGetValueW( key, NULL, wszCodebase, RRF_RT_REG_SZ, NULL, codebase, &dwBufLen); ++ if(res == ERROR_SUCCESS) ++ { ++ /* Strip file:/// */ ++ if(strncmpW(codebase, wszFileSlash, strlenW(wszFileSlash)) == 0) ++ offset = strlenW(wszFileSlash); ++ ++ strcpyW(filename, codebase + offset); ++ } ++ else ++ { ++ WCHAR assemblyname[MAX_PATH + 8]; + +- strcpyW(filename, codebase + offset); ++ hr = CLASS_E_CLASSNOTAVAILABLE; ++ WARN("CodeBase value cannot be found, trying Assembly.\n"); ++ /* get the last subkey of InprocServer32 */ ++ res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0); ++ if (res != ERROR_SUCCESS || numKeys == 0) ++ goto cleanup; ++ numKeys--; ++ keyLength = sizeof(subkeyName) / sizeof(WCHAR); ++ res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0); ++ if (res != ERROR_SUCCESS) ++ goto cleanup; ++ res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey); ++ if (res != ERROR_SUCCESS) ++ goto cleanup; ++ dwBufLen = MAX_PATH + 8; ++ res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen); ++ RegCloseKey(subkey); ++ if (res != ERROR_SUCCESS) ++ goto cleanup; ++ ++ hr = get_file_from_strongname(assemblyname, filename, MAX_PATH); ++ if (FAILED(hr)) ++ { ++ /* ++ * The registry doesn't have a CodeBase entry and it's not in the GAC. ++ * ++ * Use the Assembly Key to retrieve the filename. ++ * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null ++ */ ++ WCHAR *ns; ++ ++ WARN("Attempt to load from the application directory.\n"); ++ GetModuleFileNameW(NULL, filename, MAX_PATH); ++ ns = strrchrW(filename, '\'); ++ *(ns+1) = '\0'; ++ ++ ns = strchrW(assemblyname, ','); ++ *(ns) = '\0'; ++ strcatW(filename, assemblyname); ++ *(ns) = '.'; ++ strcatW(filename, wszDLL); ++ } ++ } + } + else + { +- WCHAR assemblyname[MAX_PATH + 8]; +- +- hr = CLASS_E_CLASSNOTAVAILABLE; +- WARN("CodeBase value cannot be found, trying Assembly.\n"); +- /* get the last subkey of InprocServer32 */ +- res = RegQueryInfoKeyW(key, 0, 0, 0, &numKeys, 0, 0, 0, 0, 0, 0, 0); +- if (res != ERROR_SUCCESS || numKeys == 0) +- goto cleanup; +- numKeys--; +- keyLength = sizeof(subkeyName) / sizeof(WCHAR); +- res = RegEnumKeyExW(key, numKeys, subkeyName, &keyLength, 0, 0, 0, 0); +- if (res != ERROR_SUCCESS) +- goto cleanup; +- res = RegOpenKeyExW(key, subkeyName, 0, KEY_READ, &subkey); +- if (res != ERROR_SUCCESS) +- goto cleanup; +- dwBufLen = MAX_PATH + 8; +- res = RegGetValueW(subkey, NULL, wszAssembly, RRF_RT_REG_SZ, NULL, assemblyname, &dwBufLen); +- RegCloseKey(subkey); +- if (res != ERROR_SUCCESS) +- goto cleanup; ++ if (!try_create_registration_free_com(riid, classname, filename)) ++ return CLASS_E_CLASSNOTAVAILABLE; + +- hr = get_file_from_strongname(assemblyname, filename, MAX_PATH); +- if (FAILED(hr)) +- { +- /* +- * The registry doesn't have a CodeBase entry and it's not in the GAC. +- * +- * Use the Assembly Key to retrieve the filename. +- * Assembly : REG_SZ : AssemblyName, Version=X.X.X.X, Culture=neutral, PublicKeyToken=null +- */ +- WCHAR *ns; +- +- WARN("Attempt to load from the application directory.\n"); +- GetModuleFileNameW(NULL, filename, MAX_PATH); +- ns = strrchrW(filename, '\'); +- *(ns+1) = '\0'; +- +- ns = strchrW(assemblyname, ','); +- *(ns) = '\0'; +- strcatW(filename, assemblyname); +- *(ns) = '.'; +- strcatW(filename, wszDLL); +- } ++ TRACE("classname (%s)\n", debugstr_w(classname)); + } + + TRACE("filename (%s)\n", debugstr_w(filename)); diff --git a/dlls/sxs/sxs.c b/dlls/sxs/sxs.c index 06e6672dbf..7eec772de1 100644 --- a/dlls/sxs/sxs.c +++ b/dlls/sxs/sxs.c @@ -23,6 +23,10 @@ #include "windef.h" #include "winbase.h"
+#include "wine/heap.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(sxs);
/*********************************************************************** * DllMain (SXS.@) @@ -40,3 +44,147 @@ BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) } return TRUE; } + +typedef struct _SXS_GUID_INFORMATION_CLR +{ + DWORD cbSize; + DWORD dwFlags; + PCWSTR pcwszRuntimeVersion; + PCWSTR pcwszTypeName; + PCWSTR pcwszAssemblyIdentity; +} SXS_GUID_INFORMATION_CLR, *PSXS_GUID_INFORMATION_CLR; + +#define SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE 0x1 +#define SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS 0x2 + +#define SXS_LOOKUP_CLR_GUID_USE_ACTCTX 0x00000001 +#define SXS_LOOKUP_CLR_GUID_FIND_SURROGATE 0x00010000 +#define SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS 0x00020000 + +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; + ULONG clrdata_len; + ULONG clrdata_offset; + DWORD miscstatus; + DWORD miscstatuscontent; + DWORD miscstatusthumbnail; + DWORD miscstatusicon; + DWORD miscstatusdocprint; +}; + +struct clrclass_data +{ + ULONG size; + DWORD res[2]; + ULONG module_len; + ULONG module_offset; + ULONG name_len; + ULONG name_offset; + ULONG version_len; + ULONG version_offset; + DWORD res2[2]; +}; + +BOOL WINAPI SxsLookupClrGuid(DWORD flags, GUID *clsid, HANDLE actctx, void *buffer, SIZE_T buffer_len, SIZE_T *buffer_len_required) +{ + ACTCTX_SECTION_KEYED_DATA guid_info = { sizeof(ACTCTX_SECTION_KEYED_DATA) }; + ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *assembly_info; + SIZE_T bytes_assembly_info; + struct comclassredirect_data *redirect_data; + struct clrclass_data *class_data; + int len_version = 0, len_name, len_identity; + const void *ptr_name, *ptr_version, *ptr_identity; + SXS_GUID_INFORMATION_CLR *ret = buffer; + char *ret_strings; + + TRACE("(%x, %s, %p, %p, %08lx, %p): stub\n", flags, wine_dbgstr_guid(clsid), actctx, buffer, buffer_len, buffer_len_required); + + if (flags & (~SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS)) + FIXME("Ignored flags: %x\n", flags & (~SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS)); + + if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, clsid, &guid_info)) + { + SetLastError(ERROR_NOT_FOUND); + return FALSE; + } + + QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, + AssemblyDetailedInformationInActivationContext, NULL, 0, &bytes_assembly_info); + if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) + { + ERR("QueryActCtxW failed: %d!\n", GetLastError()); + ReleaseActCtx(guid_info.hActCtx); + return FALSE; + } + assembly_info = heap_alloc(bytes_assembly_info); + if(!QueryActCtxW(0, guid_info.hActCtx, &guid_info.ulAssemblyRosterIndex, + AssemblyDetailedInformationInActivationContext, assembly_info, bytes_assembly_info, &bytes_assembly_info)) + { + ERR("QueryActCtxW failed: %d!\n", GetLastError()); + heap_free(assembly_info); + ReleaseActCtx(guid_info.hActCtx); + return FALSE; + } + + redirect_data = guid_info.lpData; + class_data = (void *)((char*)redirect_data + redirect_data->clrdata_offset); + + ptr_identity = assembly_info->lpAssemblyEncodedAssemblyIdentity; + ptr_name = (char *)class_data + class_data->name_offset; + ptr_version = (char *)class_data + class_data->version_offset; + + len_identity = assembly_info->ulEncodedAssemblyIdentityLength + sizeof(WCHAR); + len_name = class_data->name_len + sizeof(WCHAR); + if (class_data->version_len > 0) + len_version = class_data->version_len + sizeof(WCHAR); + + *buffer_len_required = sizeof(SXS_GUID_INFORMATION_CLR) + len_identity + len_version + len_name; + if (!buffer || buffer_len < *buffer_len_required) + { + SetLastError(ERROR_INSUFFICIENT_BUFFER); + heap_free(assembly_info); + ReleaseActCtx(guid_info.hActCtx); + return FALSE; + } + + ret->cbSize = sizeof(SXS_GUID_INFORMATION_CLR); + ret->dwFlags = SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS; + + /* Copy strings into buffer */ + ret_strings = (char *)ret + sizeof(SXS_GUID_INFORMATION_CLR); + + memcpy(ret_strings, ptr_identity, len_identity); + ret->pcwszAssemblyIdentity = (WCHAR *)ret_strings; + ret_strings += len_identity; + + memcpy(ret_strings, ptr_name, len_name); + ret->pcwszTypeName = (WCHAR *)ret_strings; + ret_strings += len_name; + + if (len_version > 0) + { + memcpy(ret_strings, ptr_version, len_version); + ret->pcwszRuntimeVersion = (WCHAR *)ret_strings; + } + else + ret->pcwszRuntimeVersion = NULL; + + SetLastError(0); + + ReleaseActCtx(guid_info.hActCtx); + heap_free(assembly_info); + return TRUE; +} diff --git a/dlls/sxs/sxs.spec b/dlls/sxs/sxs.spec index 2a27313427..138d68f7d7 100644 --- a/dlls/sxs/sxs.spec +++ b/dlls/sxs/sxs.spec @@ -1,2 +1,3 @@ @ stdcall CreateAssemblyCache(ptr long) @ stdcall CreateAssemblyNameObject(ptr wstr long ptr) +@ stdcall SxsLookupClrGuid(long ptr ptr ptr long ptr) diff --git a/dlls/sxs/tests/Makefile.in b/dlls/sxs/tests/Makefile.in index 34609a14ae..46b5485d29 100644 --- a/dlls/sxs/tests/Makefile.in +++ b/dlls/sxs/tests/Makefile.in @@ -1,6 +1,10 @@ TESTDLL = sxs.dll -IMPORTS = sxs +IMPORTS = sxs shlwapi
C_SRCS = \ cache.c \ - name.c + name.c \ + sxs.c + +RC_SRCS = resource.rc +IDL_SRCS = interfaces.idl \ No newline at end of file diff --git a/dlls/sxs/tests/comtest_dll.manifest b/dlls/sxs/tests/comtest_dll.manifest new file mode 100644 index 0000000000..ef6924de9e --- /dev/null +++ b/dlls/sxs/tests/comtest_dll.manifest @@ -0,0 +1,16 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <assemblyIdentity + name="comtest" + version="1.0.0.0" + type="win32" + /> + <clrClass + clsid="{2e106e50-e7a4-4489-8538-83643f100fdc}" + threadingModel="Both" + name="DLL.Test" + runtimeVersion="v4.0.0.0"> + </clrClass> + <file name="comtest.dll"> + </file> +</assembly> diff --git a/dlls/sxs/tests/comtest_exe.manifest b/dlls/sxs/tests/comtest_exe.manifest new file mode 100644 index 0000000000..bc9ce4c045 --- /dev/null +++ b/dlls/sxs/tests/comtest_exe.manifest @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"> + <dependency> + <dependentAssembly> + <assemblyIdentity + name="comtest" + version="1.0.0.0" + type="win32"/> + </dependentAssembly> + </dependency> +</assembly> diff --git a/dlls/sxs/tests/interfaces.idl b/dlls/sxs/tests/interfaces.idl new file mode 100644 index 0000000000..9e64988197 --- /dev/null +++ b/dlls/sxs/tests/interfaces.idl @@ -0,0 +1,33 @@ +/* + * Copyright 2018 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 "unknwn.idl" + +[ + object, + uuid(1dbc4491-080d-45c5-a15d-1e3c4610bdd9), + local +] +interface ITest : IUnknown { + HRESULT Func([in, out] int *i); +}; + +[ + uuid(2e106e50-e7a4-4489-8538-83643f100fdc), +] +coclass Test { interface ITest; }; diff --git a/dlls/sxs/tests/resource.rc b/dlls/sxs/tests/resource.rc new file mode 100644 index 0000000000..dd2c25bf37 --- /dev/null +++ b/dlls/sxs/tests/resource.rc @@ -0,0 +1,27 @@ +/* + * Resources for sxs test suite. + * + * Copyright 2018 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 "windef.h" + +/* @makedep: comtest_exe.manifest */ +comtest_exe.manifest RCDATA comtest_exe.manifest + +/* @makedep: comtest_dll.manifest */ +comtest_dll.manifest RCDATA comtest_dll.manifest diff --git a/dlls/sxs/tests/sxs.c b/dlls/sxs/tests/sxs.c new file mode 100644 index 0000000000..d92bfb65c1 --- /dev/null +++ b/dlls/sxs/tests/sxs.c @@ -0,0 +1,223 @@ +/* + * Copyright 2018 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 <stdio.h> + +#define COBJMACROS + +#include <windows.h> +#include <winsxs.h> +#include <corerror.h> +#include "shlwapi.h" + +#include "wine/test.h" +#include "wine/heap.h" + +#include "initguid.h" +#include "interfaces.h" + +BOOL (WINAPI *pSxsLookupClrGuid)(DWORD flags, GUID *clsid, HANDLE actctx, void *buffer, SIZE_T buffer_len, SIZE_T *buffer_len_required); + +#define SXS_LOOKUP_CLR_GUID_USE_ACTCTX 0x00000001 +#define SXS_LOOKUP_CLR_GUID_FIND_SURROGATE 0x00010000 +#define SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS 0x00020000 +#define SXS_LOOKUP_CLR_GUID_FIND_ANY (SXS_LOOKUP_CLR_GUID_FIND_SURROGATE | SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS) + +#define SXS_GUID_INFORMATION_CLR_FLAG_IS_SURROGATE 0x00000001 +#define SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS 0x00000002 + +typedef struct _SXS_GUID_INFORMATION_CLR +{ + DWORD cbSize; + DWORD dwFlags; + PCWSTR pcwszRuntimeVersion; + PCWSTR pcwszTypeName; + PCWSTR pcwszAssemblyIdentity; +} SXS_GUID_INFORMATION_CLR; + +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) 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; + + strcpy(path_file, path_tmp); + PathAppendA(path_file, 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 run_test(void) +{ + SIZE_T buffer_size; + BOOL ret; + SXS_GUID_INFORMATION_CLR *info; + WCHAR expected_type_name[] = {'D','L','L','.','T','e','s','t',0}; + WCHAR expected_runtime_version[] = {'v','4','.','0','.','0','.','0',0}; + WCHAR expected_assembly_identity[] = {'c','o','m','t','e','s','t',',','t','y','p','e','=','"','w','i','n','3','2','"',',','v','e','r','s','i','o','n','=','"','1','.','0','.','0','.','0','"',0}; + + ret = pSxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, NULL, 0, &buffer_size); + ok(ret == FALSE, "Got %d\n", ret); + ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "Got %d\n", GetLastError()); + + info = heap_alloc(buffer_size); + ret = pSxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, info, buffer_size, &buffer_size); + ok(ret == TRUE, "Got %d\n", ret); + ok(GetLastError() == 0, "Got %d\n", GetLastError()); + + ok(info->dwFlags == SXS_GUID_INFORMATION_CLR_FLAG_IS_CLASS, "Got %d\n", info->dwFlags); + ok(lstrcmpW(info->pcwszTypeName, expected_type_name) == 0, "Got %s\n", wine_dbgstr_w(info->pcwszTypeName)); + ok(lstrcmpW(info->pcwszAssemblyIdentity, expected_assembly_identity) == 0, "Got %s\n", wine_dbgstr_w(info->pcwszAssemblyIdentity)); + ok(lstrcmpW(info->pcwszRuntimeVersion, expected_runtime_version) == 0, "Got %s\n", wine_dbgstr_w(info->pcwszRuntimeVersion)); + + heap_free(info); +} + +static void prepare_and_run_test(void) +{ + char path_tmp[MAX_PATH] = {0}; + char path_manifest_dll[MAX_PATH] = {0}; + char path_manifest_exe[MAX_PATH] = {0}; + BOOL success; + ACTCTXA context = {0}; + ULONG_PTR cookie; + HANDLE handle_context = 0; + + GetTempPathA(MAX_PATH, path_tmp); + + if (!write_resource_file(path_tmp, "comtest_exe.manifest", "exe.manifest", path_manifest_exe)) + { + ok(0, "Failed to create file for testing\n"); + goto cleanup; + } + + if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll)) + { + ok(0, "Failed to create file for testing\n"); + goto cleanup; + } + + context.cbSize = sizeof(ACTCTXA); + context.lpSource = path_manifest_exe; + context.lpAssemblyDirectory = path_tmp; + context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID; + + handle_context = CreateActCtxA(&context); + ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "CreateActCtxA failed: %d\n", GetLastError()); + + if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE) + { + ok(0, "Failed to create activation context\n"); + goto cleanup; + } + + success = ActivateActCtx(handle_context, &cookie); + ok(success, "ActivateActCtx failed: %d\n", GetLastError()); + + run_test(); + +cleanup: + if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE) + { + success = DeactivateActCtx(0, cookie); + ok(success, "DeactivateActCtx failed: %d\n", GetLastError()); + ReleaseActCtx(handle_context); + } + if (*path_manifest_exe) + { + success = DeleteFileA(path_manifest_exe); + ok(success, "DeleteFileA failed: %d\n", GetLastError()); + } + if(*path_manifest_dll) + { + success = DeleteFileA(path_manifest_dll); + ok(success, "DeleteFileA failed: %d\n", GetLastError()); + } +} + +static void run_child_process(void) +{ + 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 %s", argv[0], argv[1], "subtest"); + + 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); +} + +static void test_SxsLookupClrGuid(void) +{ + SIZE_T buffer_size; + BOOL ret; + + ret = pSxsLookupClrGuid(SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS, (GUID*)&CLSID_Test, NULL, NULL, 0, &buffer_size); + ok(ret == FALSE, "Expected FALSE, got %d\n", ret); + ok(GetLastError() == ERROR_NOT_FOUND, "Expected ERROR_NOT_FOUND, got %d\n", GetLastError()); + + run_child_process(); +} + +START_TEST(sxs) +{ + int argc; + char **argv; + + pSxsLookupClrGuid = (void *)GetProcAddress(LoadLibraryA("sxs.dll"), "SxsLookupClrGuid"); + + argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + prepare_and_run_test(); + return; + } + + test_SxsLookupClrGuid(); +}
On 16/08/18 19:21, Fabian Maurer wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de
dlls/mscoree/corruntimehost.c.rej | 145 ++++++++++++++++++
You seem to have an extraneous file here.