[PATCH v6 2/3] mscoree: Allow loading of registration free .NET COM objects

Fabian Maurer dark.shadow4 at web.de
Sat Nov 3 07:24:30 CDT 2018


Signed-off-by: Fabian Maurer <dark.shadow4 at web.de>
---
 dlls/mscoree/corruntimehost.c | 219 ++++++++++++++++++++++++----------
 dlls/mscoree/tests/comtest.c  |   4 +-
 2 files changed, 160 insertions(+), 63 deletions(-)

diff --git a/dlls/mscoree/corruntimehost.c b/dlls/mscoree/corruntimehost.c
index 5c4e7f1d6e..ef4685822d 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,57 @@ 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, UINT filename_size)
+{
+    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);
+
+    GetModuleFileNameW(NULL, filename, filename_size);
+    PathRemoveFileSpecW(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 +1730,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, sizeof(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 e9812eb6b9..bd1632300a 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.18.0




More information about the wine-devel mailing list