[PATCH] compobj.dll16: Implement CoGetClassObject().

Zebediah Figura z.figura12 at gmail.com
Sat Feb 4 19:47:32 CST 2017


Fixes bug https://bugs.winehq.org/show_bug.cgi?id=41209

Signed-off-by: Zebediah Figura <z.figura12 at gmail.com>
---
 dlls/compobj.dll16/compobj.c          | 242 +++++++++++++++++++++++++++++++---
 dlls/compobj.dll16/compobj.dll16.spec |   2 +-
 2 files changed, 222 insertions(+), 22 deletions(-)

diff --git a/dlls/compobj.dll16/compobj.c b/dlls/compobj.dll16/compobj.c
index b934a06..1b100c3 100644
--- a/dlls/compobj.dll16/compobj.c
+++ b/dlls/compobj.dll16/compobj.c
@@ -30,6 +30,8 @@
 #include <string.h>
 #include <assert.h>
 
+#define COBJMACROS
+
 #include "windef.h"
 #include "winbase.h"
 #include "winuser.h"
@@ -42,6 +44,7 @@
 #include "wtypes.h"
 #include "wine/unicode.h"
 #include "wine/winbase16.h"
+#include "wine/list.h"
 
 #include "wine/debug.h"
 
@@ -98,6 +101,115 @@ static inline IMalloc16Impl *impl_from_IMalloc16(IMalloc16 *iface)
         return CONTAINING_RECORD(iface, IMalloc16Impl, IMalloc16_iface);
 }
 
+typedef HRESULT (CALLBACK *DllGetClassObjectFunc)(REFCLSID clsid, REFIID iid, LPVOID *ppv);
+typedef HRESULT (WINAPI *DllCanUnloadNowFunc)(void);
+
+typedef struct tagOpenDll
+{
+    LONG refs;
+    LPSTR library_name;
+    HMODULE16 library;
+    DllGetClassObjectFunc DllGetClassObject;
+    DllCanUnloadNowFunc DllCanUnloadNow;
+    struct list entry;
+} OpenDll;
+
+static struct list openDllList = LIST_INIT(openDllList);
+
+/*****************************************************************************
+ * This section contains OpenDllList implementation
+ */
+
+static OpenDll *COMPOBJ16_DllList_Get(LPCSTR library_name)
+{
+    OpenDll *ptr;
+    LIST_FOR_EACH_ENTRY(ptr, &openDllList, OpenDll, entry)
+    {
+        if (!strcasecmp(library_name, ptr->library_name) &&
+            ++(ptr->refs) != 1) /* entry is being destroy if == 1 */
+            return ptr;
+    }
+
+    return NULL;
+}
+
+static HRESULT COMPOBJ16_DllList_Add(LPCSTR library_name, OpenDll **ret)
+{
+    OpenDll *entry;
+    int len;
+    HRESULT hr = S_OK;
+    HMODULE16 hLibrary;
+    DllCanUnloadNowFunc DllCanUnloadNow;
+    DllGetClassObjectFunc DllGetClassObject;
+
+    *ret = COMPOBJ16_DllList_Get(library_name);
+    if (*ret)
+    {
+        TRACE("found %s already loaded\n", debugstr_a(library_name));
+        return S_OK;
+    }
+
+    hLibrary = LoadLibrary16(library_name);
+    if (!hLibrary)
+    {
+        ERR("couldn't load in-process dll %s\n", debugstr_a(library_name));
+        /* failure: DLL could not be loaded */
+        return E_ACCESSDENIED; /* FIXME: or should this be CO_E_DLLNOTFOUND? */
+    }
+
+    DllCanUnloadNow = (void *)GetProcAddress16(hLibrary, "DllCanUnloadNow");
+    /* Note: failing to find DllCanUnloadNow is not a failure */
+    DllGetClassObject = (void *)GetProcAddress16(hLibrary, "DllGetClassObject");
+    if (!DllGetClassObject)
+    {
+        /* failure: the dll did not export DllGetClassObject */
+        ERR("couldn't find function DllGetClassObject in %s\n", debugstr_a(library_name));
+        FreeLibrary16(hLibrary);
+        return CO_E_DLLNOTFOUND;
+    }
+
+    len = strlen(library_name);
+    entry = HeapAlloc(GetProcessHeap(),0, sizeof(OpenDll));
+    if (entry)
+        entry->library_name = HeapAlloc(GetProcessHeap(), 0, (len + 1)*sizeof(char));
+    if (entry && entry->library_name)
+    {
+        memcpy(entry->library_name, library_name, (len + 1)*sizeof(char));
+        entry->library = hLibrary;
+        entry->refs = 1;
+        entry->DllCanUnloadNow = DllCanUnloadNow;
+        entry->DllGetClassObject = DllGetClassObject;
+        list_add_tail(&openDllList, &entry->entry);
+        *ret = entry;
+
+        TRACE("added new loaded dll %s\n", debugstr_a(library_name));
+    }
+    else
+    {
+        HeapFree(GetProcessHeap(), 0, entry);
+        hr = E_OUTOFMEMORY;
+        FreeLibrary16(hLibrary);
+    }
+
+    return hr;
+}
+
+/* pass FALSE for free_entry to release a reference without destroying the
+ * entry if it reaches zero or TRUE otherwise */
+static void COMPOBJ16_DllList_ReleaseRef(OpenDll *entry)
+{
+    if (--(entry->refs) == 0)
+    {
+        list_remove(&entry->entry);
+
+        TRACE("freeing %x\n", entry->library);
+        FreeLibrary16(entry->library);
+
+        HeapFree(GetProcessHeap(), 0, entry->library_name);
+        HeapFree(GetProcessHeap(), 0, entry);
+    }
+}
+
 /******************************************************************************
  *		IMalloc16_QueryInterface	[COMPOBJ.500]
  */
@@ -279,13 +391,34 @@ HRESULT WINAPI CoCreateStandardMalloc16(DWORD dwMemContext,
     return S_OK;
 }
 
+/***********************************************************************
+ *           CoFreeAllLibraries [COMPOBJ.12]
+ */
+void WINAPI CoFreeAllLibraries16(void)
+{
+    OpenDll *entry, *next;
+
+    TRACE("()\n");
+    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &openDllList, OpenDll, entry)
+    {
+        list_remove(&entry->entry);
+
+        TRACE("freeing %x\n", entry->library);
+        FreeLibrary16(entry->library);
+
+        HeapFree(GetProcessHeap(), 0, entry->library_name);
+        HeapFree(GetProcessHeap(), 0, entry);
+    }
+}
+
 /******************************************************************************
- *		CoInitialize	[COMPOBJ.2]
+ *              CoInitialize    [COMPOBJ.2]
  * Set the win16 IMalloc used for memory management
  */
 HRESULT WINAPI CoInitialize16(
-	LPVOID lpReserved	/* [in] pointer to win16 malloc interface */
-) {
+    LPVOID lpReserved)  /* [in] pointer to win16 malloc interface */
+{
+    TRACE("()\n");
     currentMalloc16 = (LPMALLOC16)lpReserved;
     return S_OK;
 }
@@ -298,8 +431,8 @@ HRESULT WINAPI CoInitialize16(
  */
 void WINAPI CoUninitialize16(void)
 {
-  TRACE("()\n");
-  CoFreeAllLibraries();
+    TRACE("()\n");
+    CoFreeAllLibraries16();
 }
 
 /***********************************************************************
@@ -307,7 +440,18 @@ void WINAPI CoUninitialize16(void)
  */
 void WINAPI CoFreeUnusedLibraries16(void)
 {
-    CoFreeUnusedLibraries();
+    OpenDll *entry, *next;
+
+    TRACE("()\n");
+    LIST_FOR_EACH_ENTRY_SAFE(entry, next, &openDllList, OpenDll, entry)
+    {
+        if (entry->DllCanUnloadNow &&
+            WOWCallback16Ex((DWORD)entry->DllCanUnloadNow, WCB16_PASCAL, 0, NULL, NULL))
+        {
+            list_remove(&entry->entry);
+            COMPOBJ16_DllList_ReleaseRef(entry);
+        }
+    }
 }
 
 /***********************************************************************
@@ -715,14 +859,65 @@ HRESULT WINAPI CoFileTimeNow16( FILETIME *lpFileTime )
  */
 HRESULT WINAPI CoGetClassObject16(
     REFCLSID rclsid, DWORD dwClsContext, COSERVERINFO *pServerInfo,
-    REFIID iid, LPVOID *ppv)
+    REFIID riid, LPVOID *ppv)
 {
-    FIXME(", stub!\n\tCLSID:\t%s,\n\tIID:\t%s\n", debugstr_guid(rclsid), debugstr_guid(iid));
+    HRESULT hres = E_UNEXPECTED;
+
+    TRACE("CLSID: %s,IID: %s\n", debugstr_guid(rclsid), debugstr_guid(riid));
+
+    *ppv = NULL;
 
     if (pServerInfo) {
-	FIXME("\tpServerInfo: name=%s\n",debugstr_w(pServerInfo->pwszName));
-	FIXME("\t\tpAuthInfo=%p\n",pServerInfo->pAuthInfo);
+        FIXME("pServerInfo->name=%s pAuthInfo=%p\n",
+              debugstr_w(pServerInfo->pwszName), pServerInfo->pAuthInfo);
     }
+
+    if (CLSCTX_INPROC_SERVER & dwClsContext)
+    {
+        char idstr[CHARS_IN_GUID];
+        char buf_key[CHARS_IN_GUID+19], dllpath[MAX_PATH+1];
+        LONG dllpath_len = sizeof(dllpath);
+        OpenDll *dll;
+        SEGPTR seg_rclsid = MapLS(rclsid);
+        SEGPTR seg_riid   = MapLS(riid);
+        SEGPTR seg_ppv    = MapLS(ppv);
+        WORD args[6];
+        DWORD dwRet;
+
+        hres = StringFromGUID216(rclsid, idstr, CHARS_IN_GUID);
+        sprintf(buf_key, "CLSID\\%s\\InprocServer", idstr);
+        if (RegQueryValueA(HKEY_CLASSES_ROOT, buf_key, dllpath, &dllpath_len))
+        {
+            ERR("class %s not registered\n", debugstr_guid(rclsid));
+            return REGDB_E_CLASSNOTREG;
+        }
+
+        hres = COMPOBJ16_DllList_Add(dllpath, &dll);
+        if (FAILED(hres))
+            return hres;
+
+        TRACE("calling DllGetClassObject %p\n", dll->DllGetClassObject);
+        args[5] = SELECTOROF(seg_rclsid);
+        args[4] = OFFSETOF(seg_rclsid);
+        args[3] = SELECTOROF(seg_riid);
+        args[2] = OFFSETOF(seg_riid);
+        args[1] = SELECTOROF(seg_ppv);
+        args[0] = OFFSETOF(seg_ppv);
+        WOWCallback16Ex((DWORD)dll->DllGetClassObject, WCB16_PASCAL, sizeof(args), args, &dwRet);
+        if (dwRet != S_OK)
+        {
+            ERR("DllGetClassObject returned error 0x%08x\n", dwRet);
+            return dwRet;
+        }
+
+        UnMapLS(seg_rclsid);
+        UnMapLS(seg_riid);
+        UnMapLS(seg_ppv);
+
+        return S_OK;
+    }
+
+    FIXME("semi-stub\n");
     return E_NOTIMPL;
 }
 
@@ -738,17 +933,22 @@ HRESULT WINAPI CoCreateGuid16(GUID *pguid)
  *           CoCreateInstance [COMPOBJ.13]
  */
 HRESULT WINAPI CoCreateInstance16(
-	REFCLSID rclsid,
-	LPUNKNOWN pUnkOuter,
-	DWORD dwClsContext,
-	REFIID iid,
-	LPVOID *ppv)
-{
-  FIXME("(%s, %p, %x, %s, %p), stub!\n",
-	debugstr_guid(rclsid), pUnkOuter, dwClsContext, debugstr_guid(iid),
-	ppv
-  );
-  return E_NOTIMPL;
+        REFCLSID rclsid,
+        LPUNKNOWN pUnkOuter,
+        DWORD dwClsContext,
+        REFIID riid,
+        LPVOID *ppv)
+{
+    IClassFactory *cf;
+    HRESULT hres;
+
+    hres = CoGetClassObject16(rclsid, dwClsContext, NULL, &IID_IClassFactory, (void **)&cf);
+    if (FAILED(hres))
+        return hres;
+
+    hres = IClassFactory_CreateInstance(cf, pUnkOuter, riid, ppv);
+    IClassFactory_Release(cf);
+    return hres;
 }
 
 /***********************************************************************
diff --git a/dlls/compobj.dll16/compobj.dll16.spec b/dlls/compobj.dll16/compobj.dll16.spec
index 85dfc42..2c23f2d 100644
--- a/dlls/compobj.dll16/compobj.dll16.spec
+++ b/dlls/compobj.dll16/compobj.dll16.spec
@@ -9,7 +9,7 @@
 9 stub COUNMARSHALINTERFACE
 10 stub COLOADLIBRARY
 11 stub COFREELIBRARY
-12 stub COFREEALLLIBRARIES
+12 pascal CoFreeAllLibraries() CoFreeAllLibraries16
 13 pascal CoCreateInstance(ptr ptr long ptr ptr) CoCreateInstance16
 14 stub STRINGFROMIID
 15 pascal CoDisconnectObject(ptr long) CoDisconnectObject16
-- 
2.7.4




More information about the wine-patches mailing list