Signed-off-by: Fabian Maurer dark.shadow4@web.de --- v8: In size calculation don't count null terminator twice --- dlls/mscoree/corruntimehost.c | 237 +++++++++++++++++++++++++--------- dlls/mscoree/tests/comtest.c | 4 +- 2 files changed, 178 insertions(+), 63 deletions(-)
diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c index 5c4e7f1d6e..57d12bab3b 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,75 @@ HRESULT RuntimeHost_GetInterface(RuntimeHost *This, REFCLSID clsid, REFIID riid, return CLASS_E_CLASSNOTAVAILABLE; }
+static BOOL try_create_registration_free_com(REFIID clsid, WCHAR *classname, UINT classname_size, WCHAR *filename, UINT filename_size) +{ + ACTCTX_SECTION_KEYED_DATA guid_info = { sizeof(ACTCTX_SECTION_KEYED_DATA) }; + ACTIVATION_CONTEXT_ASSEMBLY_DETAILED_INFORMATION *assembly_info = NULL; + 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}; + BOOL ret = FALSE; + + 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); + goto end; + } + + 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()); + goto end; + } + + redirect_data = guid_info.lpData; + class_data = (void *)((char *)redirect_data + redirect_data->clrdata_offset); + + ptr_name = (char *)class_data + class_data->name_offset; + if (lstrlenW(ptr_name) + 2 >= classname_size) /* Include null-terminator */ + { + ERR("Buffer is too small\n"); + goto end; + } + 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); + + GetModuleFileNameW(NULL, filename, filename_size); + PathRemoveFileSpecW(filename); + + if (lstrlenW(filename) + lstrlenW(path) + ARRAY_SIZE(str_dll) + 2 >= filename_size) /* Include blackslash */ + { + ERR("Buffer is too small\n"); + goto end; + } + + PathAppendW(filename, path); + strcatW(filename, str_dll); + + ret = TRUE; + +end: + if (assembly_info) + heap_free(assembly_info); + + if (guid_info.hActCtx) + ReleaseActCtx(guid_info.hActCtx); + + return ret; +} + #define CHARS_IN_GUID 39
HRESULT create_monodata(REFIID riid, LPVOID *ppObj ) @@ -1640,75 +1748,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); + strcpyW(filename, codebase + offset); + } + 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; + + 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, ARRAY_SIZE(classname), filename, ARRAY_SIZE(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 eec5d9a857..4879e3b762 100644 --- a/dlls/mscoree/tests/comtest.c +++ b/dlls/mscoree/tests/comtest.c @@ -114,7 +114,7 @@ static void run_test(BOOL expect_success) HRESULT result_expected = expect_success ? S_OK : HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
hr = CoCreateInstance(&CLSID_Test, NULL, CLSCTX_INPROC_SERVER, &IID_ITest, (void**)&test); - todo_wine + todo_wine_if(!expect_success) ok(hr == result_expected, "Expected %x, got %x\n", result_expected, hr);
if (hr == S_OK) @@ -135,7 +135,7 @@ static void run_test(BOOL expect_success) { ITest *test2 = NULL; hr = IClassFactory_CreateInstance(classFactory, NULL, &IID_ITest, (void **)&test2); - todo_wine + todo_wine_if(!expect_success) ok(hr == S_OK, "Got %x\n", hr);
if (hr == S_OK) -- 2.20.1
Signed-off-by: Vincent Povirk vincent@codeweavers.com
I'm still unsure of the size calculation for the path. You're adding 2 characters, but afaict it's only to account for a single backslash. I'm signing off anyway because being too cautious by one character in the filename seems acceptable to me. The tests pass using wine-mono from the master branch, and it looks correct to me otherwise.
I see my mistake, you used >= for the size check when I expected (and assumed) >. The size checks look correct to me now. The style is a little strange, though, with the code calculating the minimum size that would overrun the buffer, rather than required buffer size. I'd prefer it be changed for readability, if you don't mind.
Sure, I don't mind. If you don't mind the question, how would you write it?
Regards, Fabian Maurer
Calculate required buffer size, compare to actual
buffer size.
Ah yes, sorry got confused there for a moment. I sent an updated patch to do the calculation properly.
Regards,Fabian Maurer