Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de --- v2: Fix test not working when not in root folder Fix cleanup sometimes failing due to race condition
v3: Build c# dll during test --- dlls/mscoree/tests/Makefile.in | 4 + dlls/mscoree/tests/comtest.c | 299 ++++++++++++++++++++++++ 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, 416 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..687149cf57 --- /dev/null +++ b/dlls/mscoree/tests/comtest.c @@ -0,0 +1,299 @@ +/* + * 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(int run) +{ + 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); + } + + 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); + } + } +} + +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(int run, 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)) + { + skip("run %d: Failed to create file for testing\n", run); + 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)) + { + skip("run %d: Failed to create file for testing\n", run); + goto cleanup; + } + + if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll)) + { + skip("run %d: Failed to create file for testing\n", run); + 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); + todo_wine + ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "run %d: CreateActCtxA failed: %d\n", run, GetLastError()); + + if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE) + { + skip("Failed to create activation context\n"); + goto cleanup; + } + + success = ActivateActCtx(handle_context, &cookie); + ok(success, "run %d: ActivateActCtx failed: %d\n", run, GetLastError()); + + run_test(run); + +cleanup: + if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE) + { + success = DeactivateActCtx(0, cookie); + ok(success, "run %d: DeactivateActCtx failed: %d\n", run, GetLastError()); + ReleaseActCtx(handle_context); + } + if (*path_manifest_exe) + { + success = DeleteFileA(path_manifest_exe); + ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); + } + if(*path_manifest_dll) + { + success = DeleteFileA(path_manifest_dll); + ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); + } + if(*path_dll_source) + { + success = DeleteFileA(path_dll_source); + ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); + } + /* dll cleanup is handled by the parent, because it might still be used by the child */ +} + + +static void cleanup_test(int run) +{ + 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, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); +} + +static void run_child_process(int run, 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 %d %s", argv[0], argv[1], run, 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(run); +} + +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) + { + int run = atoi(argv[2]); + const char *dll_source = argv[3]; + prepare_and_run_test(run, dll_source); + + goto cleanup; + } + + run_child_process(1, "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
Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/mscoree/tests/comtest.c | 1 - dlls/ntdll/actctx.c | 5 ++++- 2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/dlls/mscoree/tests/comtest.c b/dlls/mscoree/tests/comtest.c index 687149cf57..63e43f4b95 100644 --- a/dlls/mscoree/tests/comtest.c +++ b/dlls/mscoree/tests/comtest.c @@ -177,7 +177,6 @@ static void prepare_and_run_test(int run, const char *dll_source) context.dwFlags = ACTCTX_FLAG_ASSEMBLY_DIRECTORY_VALID;
handle_context = CreateActCtxA(&context); - todo_wine ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "run %d: CreateActCtxA failed: %d\n", run, GetLastError());
if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE) diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 7e3aec4d1e..92fa16fb71 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -3294,7 +3294,10 @@ 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 == 0) + break; + else + continue; } RtlFreeUnicodeString( &nameW ); }
How is that specific to .NET assemblies, i.e. why tests are in mscoree and not in kernel32 itself?
On Dienstag, 7. August 2018 19:52:03 CEST Nikolay Sivov wrote:
How is that specific to .NET assemblies, i.e. why tests are in mscoree and not in kernel32 itself?
It's not specific to .NET assemblies, the tests I wrote just happen to run into this issue. I just didn't want to copy the whole test into kernel32 for a small issue like that.
Regards, Fabian Maurer
On 8/7/2018 8:56 PM, Fabian Maurer wrote:
On Dienstag, 7. August 2018 19:52:03 CEST Nikolay Sivov wrote:
How is that specific to .NET assemblies, i.e. why tests are in mscoree
and not in kernel32 itself?
It's not specific to .NET assemblies,
the tests I wrote just happen to run into this issue.
I just didn't want to copy the whole test into
kernel32 for a small issue like that.
If it's a general issue it should go to kernel32 tests.
Regards,
Fabian Maurer
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 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 0c933cac29..cd9c1c3234 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 );
@@ -1606,6 +1608,93 @@ HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, return CLASS_E_CLASSNOTAVAILABLE; }
+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 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 = 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/mscoree/tests/comtest.c b/dlls/mscoree/tests/comtest.c index 63e43f4b95..a73a7fc5fc 100644 --- a/dlls/mscoree/tests/comtest.c +++ b/dlls/mscoree/tests/comtest.c @@ -70,7 +70,6 @@ static void run_test(int run) 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) @@ -89,7 +88,6 @@ static void run_test(int run) { ITest *test2 = NULL; hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2); - todo_wine ok(hr == S_OK, "Got %x\n", hr);
if (test2)
The patch doesn't apply.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de --- 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 | 228 ++++++++++++++++++++++++++++ 6 files changed, 321 insertions(+), 2 deletions(-) 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/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..a68876d422 --- /dev/null +++ b/dlls/sxs/tests/sxs.c @@ -0,0 +1,228 @@ +/* + * 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 *SxsLookupClrGuid)(DWORD dwFlags, LPGUID pClsid, HANDLE hActCtx, VOID *pvOutputBuffer, SIZE_T cbOutputBuffer, PSIZE_T pcbOutputBuffer); + +#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, *PSXS_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(int run) +{ + 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 = SxsLookupClrGuid(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 = SxsLookupClrGuid(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(int run) +{ + 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)) + { + skip("run %d: Failed to create file for testing\n", run); + goto cleanup; + } + + if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll)) + { + skip("run %d: Failed to create file for testing\n", run); + 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, "run %d: CreateActCtxA failed: %d\n", run, GetLastError()); + + if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE) + { + skip("Failed to create activation context\n"); + goto cleanup; + } + + success = ActivateActCtx(handle_context, &cookie); + ok(success, "run %d: ActivateActCtx failed: %d\n", run, GetLastError()); + + run_test(run); + +cleanup: + if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE) + { + success = DeactivateActCtx(0, cookie); + ok(success, "run %d: DeactivateActCtx failed: %d\n", run, GetLastError()); + ReleaseActCtx(handle_context); + } + if (*path_manifest_exe) + { + success = DeleteFileA(path_manifest_exe); + ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); + } + if(*path_manifest_dll) + { + success = DeleteFileA(path_manifest_dll); + ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError()); + } +} + +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); +} + +static void test_SxsLookupClrGuid(void) +{ + SIZE_T buffer_size; + BOOL ret; + + ret = SxsLookupClrGuid(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(1); +} + +START_TEST(sxs) +{ + int argc; + char **argv; + + SxsLookupClrGuid = (void *)GetProcAddress(LoadLibraryA("sxs.dll"), "SxsLookupClrGuid"); + + argc = winetest_get_mainargs(&argv); + if (argc > 2) + { + int run = atoi(argv[2]); + prepare_and_run_test(run); + + return; + } + + todo_wine + ok(SxsLookupClrGuid != NULL, "SxsLookupClrGuid doesn't exist\n"); + if( SxsLookupClrGuid) + test_SxsLookupClrGuid(); +}
On 08/07/2018 08:45 PM, Fabian Maurer wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de
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 | 228 ++++++++++++++++++++++++++++ 6 files changed, 321 insertions(+), 2 deletions(-) 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/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..a68876d422 --- /dev/null +++ b/dlls/sxs/tests/sxs.c @@ -0,0 +1,228 @@ +/*
- 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 *SxsLookupClrGuid)(DWORD dwFlags, LPGUID pClsid, HANDLE hActCtx, VOID *pvOutputBuffer, SIZE_T cbOutputBuffer, PSIZE_T pcbOutputBuffer);
Please use usual naming conventions for function pointer, and argument types.
+#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, *PSXS_GUID_INFORMATION_CLR;
Pointer type is not used.
+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(int run) +{
- 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 = SxsLookupClrGuid(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 = SxsLookupClrGuid(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(int run) +{
- 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))
- {
skip("run %d: Failed to create file for testing\n", run);
goto cleanup;
- }
- if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll))
- {
skip("run %d: Failed to create file for testing\n", run);
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, "run %d: CreateActCtxA failed: %d\n", run, GetLastError());
- if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE)
- {
skip("Failed to create activation context\n");
goto cleanup;
- }
- success = ActivateActCtx(handle_context, &cookie);
- ok(success, "run %d: ActivateActCtx failed: %d\n", run, GetLastError());
- run_test(run);
+cleanup:
- if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE)
- {
success = DeactivateActCtx(0, cookie);
ok(success, "run %d: DeactivateActCtx failed: %d\n", run, GetLastError());
ReleaseActCtx(handle_context);
- }
- if (*path_manifest_exe)
- {
success = DeleteFileA(path_manifest_exe);
ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
- }
- if(*path_manifest_dll)
- {
success = DeleteFileA(path_manifest_dll);
ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
- }
+}
+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);
+}
+static void test_SxsLookupClrGuid(void) +{
- SIZE_T buffer_size;
- BOOL ret;
- ret = SxsLookupClrGuid(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(1);
+}
+START_TEST(sxs) +{
- int argc;
- char **argv;
- SxsLookupClrGuid = (void *)GetProcAddress(LoadLibraryA("sxs.dll"), "SxsLookupClrGuid");
- argc = winetest_get_mainargs(&argv);
- if (argc > 2)
- {
int run = atoi(argv[2]);
prepare_and_run_test(run);
return;
- }
- todo_wine
- ok(SxsLookupClrGuid != NULL, "SxsLookupClrGuid doesn't exist\n");
- if( SxsLookupClrGuid)
test_SxsLookupClrGuid();
What's a point of pointer test, is it missing on some Windows versions?
+}
Please use usual naming conventions for function pointer, and argument types.
Shouldn't I keep it the function the same as it's defined?
Pointer type is not used.
Yeah, I kept the declaration the same as usual, but I can remove the pointer type.
What's a point of pointer test, is it missing on some Windows versions?
It's missing on wine, currently. How do you want me to handle that?
Regards, Fabian Maurer
On 8/7/2018 10:14 PM, Fabian Maurer wrote:
Please use usual naming conventions for function pointer, and argument
types.
Shouldn't I keep it the function the same as it's defined?
Is it defined anywhere in SDK?
Pointer type is not used.
Yeah, I kept the declaration the same as usual, but I can remove the pointer type.
What's a point of pointer test, is it missing on some Windows versions?
It's missing on wine, currently. How do you want me to handle that?
Add a stub, or merge patches.
Regards,
Fabian Maurer
Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/sxs/sxs.spec | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/dlls/sxs/sxs.spec b/dlls/sxs/sxs.spec index 2a27313427..9766c4a791 100644 --- a/dlls/sxs/sxs.spec +++ b/dlls/sxs/sxs.spec @@ -1,2 +1,21 @@ @ stdcall CreateAssemblyCache(ptr long) @ stdcall CreateAssemblyNameObject(ptr wstr long ptr) +@ stub SxsBeginAssemblyInstall +@ stub SxsEndAssemblyInstall +@ stub SxsFindClrClassInformation +@ stub SxsFindClrSurrogateInformation +@ stub SxsGenerateActivationContext +@ stub SxsInstallW +@ stub SxsLookupClrGuid +@ stub SxsOleAut32MapConfiguredClsidToReferenceClsid +@ stub SxsOleAut32MapIIDOrCLSIDToTypeLibrary +@ stub SxsOleAut32MapIIDToProxyStubCLSID +@ stub SxsOleAut32MapIIDToTLBPath +@ stub SxsOleAut32MapReferenceClsidToConfiguredClsid +@ stub SxsOleAut32RedirectTypeLibrary +@ stub SxsProbeAssemblyInstallation +@ stub SxsQueryManifestInformation +@ stub SxsRunDllInstallAssembly +@ stub SxsRunDllInstallAssemblyW +@ stub SxsUninstallW +@ stub SxspGenerateManifestPathOnAssemblyIdentity
On 08/07/2018 08:45 PM, Fabian Maurer wrote:
Signed-off-by: Fabian Maurer dark.shadow4@web.de
dlls/sxs/sxs.spec | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+)
diff --git a/dlls/sxs/sxs.spec b/dlls/sxs/sxs.spec index 2a27313427..9766c4a791 100644 --- a/dlls/sxs/sxs.spec +++ b/dlls/sxs/sxs.spec @@ -1,2 +1,21 @@ @ stdcall CreateAssemblyCache(ptr long) @ stdcall CreateAssemblyNameObject(ptr wstr long ptr) +@ stub SxsBeginAssemblyInstall +@ stub SxsEndAssemblyInstall +@ stub SxsFindClrClassInformation +@ stub SxsFindClrSurrogateInformation +@ stub SxsGenerateActivationContext +@ stub SxsInstallW +@ stub SxsLookupClrGuid +@ stub SxsOleAut32MapConfiguredClsidToReferenceClsid +@ stub SxsOleAut32MapIIDOrCLSIDToTypeLibrary +@ stub SxsOleAut32MapIIDToProxyStubCLSID +@ stub SxsOleAut32MapIIDToTLBPath +@ stub SxsOleAut32MapReferenceClsidToConfiguredClsid +@ stub SxsOleAut32RedirectTypeLibrary +@ stub SxsProbeAssemblyInstallation +@ stub SxsQueryManifestInformation +@ stub SxsRunDllInstallAssembly +@ stub SxsRunDllInstallAssemblyW +@ stub SxsUninstallW +@ stub SxspGenerateManifestPathOnAssemblyIdentity
Is this really necessary?
Is this really necessary?
Necessary for this bugfix? No. But when another unimplemented function gets called, we'll notice it fairly quick. Better than the program silently not calling it and erroring somewhere like it happened in this bug, IMHO.
Regards, Fabian Maurer
On 8/7/2018 10:16 PM, Fabian Maurer wrote:
Is this really necessary?
Necessary for this bugfix? No.
But when another unimplemented function gets called, we'll notice it fairly quick. Better than the program silently not calling it and erroring somewhere like it happened in this bug, IMHO.
The problem is that once you add a stub entry function becomes available, in this case a number of undocumented (right?) functions will at once.
Regards,
Fabian Maurer
The problem is that once you add a stub entry function
becomes
available, in this case a number of undocumented (right?)
functions will
at once.
Sorry, I don't get what you're saying. What do you mean?
Regards, Fabian Maurer
On Sun, Aug 12, 2018 at 4:00 AM Fabian Maurer dark.shadow4@web.de wrote:
The problem is that once you add a stub entry function becomes
available, in this case a number of undocumented (right?) functions will
at once.
Sorry, I don't get what you're saying. What do you mean?
If you explicitly add @stub entries in the spec file you start to generate the corresponding exports in the .dll.so. Which means that applications will start to get a successful result from e.g. GetProcAddress() for those functions, which might cause applications to try to make use of those functions and thus crash.
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de --- dlls/sxs/sxs.c | 135 +++++++++++++++++++++++++++++++++++++++++++ dlls/sxs/sxs.spec | 2 +- dlls/sxs/tests/sxs.c | 1 - 3 files changed, 136 insertions(+), 2 deletions(-)
diff --git a/dlls/sxs/sxs.c b/dlls/sxs/sxs.c index 06e6672dbf..74a2450c68 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,134 @@ 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 dwFlags, LPGUID pClsid, HANDLE hActCtx, PVOID pvOutputBuffer, SIZE_T cbOutputBuffer, PSIZE_T pcbOutputBuffer) +{ + 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 = pvOutputBuffer; + char *ret_strings = (char *)ret + sizeof(SXS_GUID_INFORMATION_CLR); + + TRACE("(%x, %s, %p, %p, %08lx, %p): stub\n", dwFlags, wine_dbgstr_guid(pClsid), hActCtx, pvOutputBuffer, cbOutputBuffer, pcbOutputBuffer); + + if (dwFlags & (~SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS)) + FIXME("Ignored flags: %x\n", dwFlags & (~SXS_LOOKUP_CLR_GUID_FIND_CLR_CLASS)); + + if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, pClsid, &guid_info)) + { + DWORD error = GetLastError(); + if (error != ERROR_SXS_KEY_NOT_FOUND) + ERR("Failed to find guid: %d\n", error); + SetLastError(ERROR_NOT_FOUND); + 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_identity = assembly_info->lpAssemblyEncodedAssemblyIdentity; + ptr_name = (char *)class_data + class_data->name_offset; + ptr_version = (char *)class_data + class_data->version_offset; + + len_identity = (lstrlenW(ptr_identity) + 1) * sizeof(WCHAR); + len_name = (lstrlenW(ptr_name) + 1) * sizeof(WCHAR); + if (class_data->version_len > 0) + len_version = (lstrlenW(ptr_version) + 1) * sizeof(WCHAR); + + *pcbOutputBuffer = sizeof(SXS_GUID_INFORMATION_CLR) + len_identity + len_version + len_name; + if (!pvOutputBuffer || cbOutputBuffer < *pcbOutputBuffer) + { + 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; + +#define copy_str(target, ptr, len) \ + target = len ? (void *)ret_strings : NULL; \ + memcpy(ret_strings, ptr, len); \ + ret_strings += len; + copy_str(ret->pcwszAssemblyIdentity, ptr_identity, len_identity); + copy_str(ret->pcwszTypeName , ptr_name, len_name); + copy_str(ret->pcwszRuntimeVersion, ptr_version, len_version); +#undef copy_str + + 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 9766c4a791..99bc917161 100644 --- a/dlls/sxs/sxs.spec +++ b/dlls/sxs/sxs.spec @@ -6,7 +6,7 @@ @ stub SxsFindClrSurrogateInformation @ stub SxsGenerateActivationContext @ stub SxsInstallW -@ stub SxsLookupClrGuid +@ stdcall SxsLookupClrGuid(long ptr ptr ptr long ptr) @ stub SxsOleAut32MapConfiguredClsidToReferenceClsid @ stub SxsOleAut32MapIIDOrCLSIDToTypeLibrary @ stub SxsOleAut32MapIIDToProxyStubCLSID diff --git a/dlls/sxs/tests/sxs.c b/dlls/sxs/tests/sxs.c index a68876d422..7b70d43dad 100644 --- a/dlls/sxs/tests/sxs.c +++ b/dlls/sxs/tests/sxs.c @@ -221,7 +221,6 @@ START_TEST(sxs) return; }
- todo_wine ok(SxsLookupClrGuid != NULL, "SxsLookupClrGuid doesn't exist\n"); if( SxsLookupClrGuid) test_SxsLookupClrGuid();
On 08/07/2018 08:45 PM, Fabian Maurer wrote:
+BOOL WINAPI SxsLookupClrGuid(DWORD dwFlags, LPGUID pClsid, HANDLE hActCtx, PVOID pvOutputBuffer, SIZE_T cbOutputBuffer, PSIZE_T pcbOutputBuffer)
Please fix argument type names.
- if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0, ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, pClsid, &guid_info))
- {
DWORD error = GetLastError();
if (error != ERROR_SXS_KEY_NOT_FOUND)
ERR("Failed to find guid: %d\n", error);
SetLastError(ERROR_NOT_FOUND);
return FALSE;
- }
This looks too complicated.
- 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))
First call should also be checked for failure.
- len_identity = (lstrlenW(ptr_identity) + 1) * sizeof(WCHAR);
- len_name = (lstrlenW(ptr_name) + 1) * sizeof(WCHAR);
- if (class_data->version_len > 0)
len_version = (lstrlenW(ptr_version) + 1) * sizeof(WCHAR);
You already have lengths of all three fields at this point.
+#define copy_str(target, ptr, len) \
target = len ? (void *)ret_strings : NULL; \
memcpy(ret_strings, ptr, len); \
ret_strings += len;
- copy_str(ret->pcwszAssemblyIdentity, ptr_identity, len_identity);
- copy_str(ret->pcwszTypeName , ptr_name, len_name);
- copy_str(ret->pcwszRuntimeVersion, ptr_version, len_version);
+#undef copy_str
Could you add a test for this layout? And probably remove a macro too.
+BOOL WINAPI SxsLookupClrGuid(DWORD dwFlags, LPGUID pClsid, HANDLE hActCtx, PVOID pvOutputBuffer, SIZE_T cbOutputBuffer, PSIZE_T pcbOutputBuffer)
Please fix argument type names.
What do you mean? I though for official API functions we keep the arguments like they are on windows?
- if (!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0,
ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, pClsid, &guid_info)) + {
DWORD error = GetLastError();
if (error != ERROR_SXS_KEY_NOT_FOUND)
ERR("Failed to find guid: %d\n", error);
SetLastError(ERROR_NOT_FOUND);
return FALSE;
- }
This looks too complicated.
Just a bit or extra error checking in case something goes wrong, but I can throw that out if you want.
First call should also be checked for failure.
Will do.
- len_identity = (lstrlenW(ptr_identity) + 1) * sizeof(WCHAR);
- len_name = (lstrlenW(ptr_name) + 1) * sizeof(WCHAR);
- if (class_data->version_len > 0)
len_version = (lstrlenW(ptr_version) + 1) * sizeof(WCHAR);
You already have lengths of all three fields at this point.
Yeah, don't know why I didn't use that.
+#define copy_str(target, ptr, len) \
target = len ? (void *)ret_strings : NULL; \
memcpy(ret_strings, ptr, len); \
ret_strings += len;
- copy_str(ret->pcwszAssemblyIdentity, ptr_identity, len_identity);
- copy_str(ret->pcwszTypeName , ptr_name, len_name);
- copy_str(ret->pcwszRuntimeVersion, ptr_version, len_version);
+#undef copy_str
Could you add a test for this layout? And probably remove a macro too.
Why add a test for the layout? All that matters is that the strings in the struct work, the rest is internals that we don't care about, no? Also, why remove the macro? It makes the code simpler, do you prefer the duplication?
Regards, Fabian Maurer
On 8/7/2018 10:26 PM, Fabian Maurer wrote:
- if
(!FindActCtxSectionGuid(FIND_ACTCTX_SECTION_KEY_RETURN_HACTCTX, 0,
ACTIVATION_CONTEXT_SECTION_COM_SERVER_REDIRECTION, pClsid,
&guid_info)) +
{
- DWORD error = GetLastError();
- if (error != ERROR_SXS_KEY_NOT_FOUND)
- ERR("Failed to find guid: %d\n", error);
- SetLastError(ERROR_NOT_FOUND);
- return FALSE;
- }
This looks too complicated.
Just a bit or extra error checking in case something goes wrong, but I can throw that out if you want.
It depends on how it should work.
The run_test function leaks COM objects.
The prepare_and_run_test function has several skips that look like failures. This should result in a test failure or at least a win_skip.
I'm not clear on what the run number is for. It doesn't seem to be used now, and the system doesn't seem to be designed for reuse otherwise. On Tue, Aug 7, 2018 at 12:45 PM Fabian Maurer dark.shadow4@web.de wrote:
Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=43270 Signed-off-by: Fabian Maurer dark.shadow4@web.de
v2: Fix test not working when not in root folder Fix cleanup sometimes failing due to race condition
v3: Build c# dll during test
dlls/mscoree/tests/Makefile.in | 4 + dlls/mscoree/tests/comtest.c | 299 ++++++++++++++++++++++++ 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, 416 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..687149cf57 --- /dev/null +++ b/dlls/mscoree/tests/comtest.c @@ -0,0 +1,299 @@ +/*
- 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(int run) +{
- 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);
- }
- 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);
}
- }
+}
+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(int run, 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))
- {
skip("run %d: Failed to create file for testing\n", run);
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))
- {
skip("run %d: Failed to create file for testing\n", run);
goto cleanup;
- }
- if (!write_resource_file(path_tmp, "comtest_dll.manifest", "comtest.manifest", path_manifest_dll))
- {
skip("run %d: Failed to create file for testing\n", run);
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);
- todo_wine
- ok(handle_context != NULL && handle_context != INVALID_HANDLE_VALUE, "run %d: CreateActCtxA failed: %d\n", run, GetLastError());
- if (handle_context == NULL || handle_context == INVALID_HANDLE_VALUE)
- {
skip("Failed to create activation context\n");
goto cleanup;
- }
- success = ActivateActCtx(handle_context, &cookie);
- ok(success, "run %d: ActivateActCtx failed: %d\n", run, GetLastError());
- run_test(run);
+cleanup:
if (handle_context != NULL && handle_context != INVALID_HANDLE_VALUE)
- {
success = DeactivateActCtx(0, cookie);
ok(success, "run %d: DeactivateActCtx failed: %d\n", run, GetLastError());
ReleaseActCtx(handle_context);
- }
- if (*path_manifest_exe)
- {
success = DeleteFileA(path_manifest_exe);
ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
- }
- if(*path_manifest_dll)
- {
success = DeleteFileA(path_manifest_dll);
ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
- }
- if(*path_dll_source)
- {
success = DeleteFileA(path_dll_source);
ok(success, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
- }
- /* dll cleanup is handled by the parent, because it might still be used by the child */
+}
+static void cleanup_test(int run) +{
- 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, "run %d: DeleteFileA failed: %d\n", run, GetLastError());
+}
+static void run_child_process(int run, 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 %d %s", argv[0], argv[1], run, 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(run);
+}
+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)
- {
int run = atoi(argv[2]);
const char *dll_source = argv[3];
prepare_and_run_test(run, dll_source);
goto cleanup;
- }
- run_child_process(1, "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
2.18.0