Robert Shearman : ole32: CoGetClassObject should host a single-threaded object in a

Alexandre Julliard julliard at wine.codeweavers.com
Sat Aug 26 13:47:40 CDT 2006


Module: wine
Branch: master
Commit: 619ba90dbecaca7b4bc360b38bd7ba45f5b82546
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=619ba90dbecaca7b4bc360b38bd7ba45f5b82546

Author: Robert Shearman <rob at codeweavers.com>
Date:   Sat Aug 26 11:42:40 2006 +0100

ole32: CoGetClassObject should host a single-threaded object in a
single-threaded apartment if executing in a multi-threaded apartment,
if one exists.

---

 dlls/ole32/compobj.c         |   77 +++++++++++++++++++++++++++++++++++++++++-
 dlls/ole32/compobj_private.h |    1 +
 2 files changed, 76 insertions(+), 2 deletions(-)

diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c
index 1f13fd0..51e942b 100644
--- a/dlls/ole32/compobj.c
+++ b/dlls/ole32/compobj.c
@@ -82,6 +82,7 @@ #define ARRAYSIZE(array) (sizeof(array)/
 
 static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN*  ppUnk);
 static void COM_RevokeAllClasses(void);
+static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID riid, void **ppv);
 
 static APARTMENT *MTA; /* protected by csApartment */
 static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
@@ -427,6 +428,57 @@ APARTMENT *apartment_findfromtid(DWORD t
     return result;
 }
 
+/* gets an apartment which has a given type. The caller must
+ * release the reference from the apartment as soon as the apartment pointer
+ * is no longer required. */
+static APARTMENT *apartment_findfromtype(BOOL multi_threaded)
+{
+    APARTMENT *result = NULL;
+    struct apartment *apt;
+
+    EnterCriticalSection(&csApartment);
+    LIST_FOR_EACH_ENTRY( apt, &apts, struct apartment, entry )
+    {
+        if (apt->multi_threaded == multi_threaded)
+        {
+            result = apt;
+            apartment_addref(result);
+            break;
+        }
+    }
+    LeaveCriticalSection(&csApartment);
+
+    return result;
+}
+
+struct host_object_params
+{
+    HKEY hkeydll;
+    CLSID clsid; /* clsid of object to marshal */
+    IID iid; /* interface to marshal */
+    IStream *stream; /* stream that the object will be marshaled into */
+};
+
+static HRESULT apartment_hostobject(const struct host_object_params *params)
+{
+    IUnknown *object;
+    HRESULT hr;
+    static const LARGE_INTEGER llZero;
+
+    TRACE("\n");
+
+    hr = get_inproc_class_object(params->hkeydll, &params->clsid, &params->iid, (void **)&object);
+    if (FAILED(hr))
+        return hr;
+
+    hr = CoMarshalInterface(params->stream, &params->iid, object, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
+    if (FAILED(hr))
+        IUnknown_Release(object);
+    IStream_Seek(params->stream, llZero, STREAM_SEEK_SET, NULL);
+
+    return hr;
+}
+
 static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
 {
     switch (msg)
@@ -434,6 +486,8 @@ static LRESULT CALLBACK apartment_wndpro
     case DM_EXECUTERPC:
         RPC_ExecuteCall((struct dispatch_params *)lParam);
         return 0;
+    case DM_HOSTOBJECT:
+        return apartment_hostobject((const struct host_object_params *)lParam);
     default:
         return DefWindowProcW(hWnd, msg, wParam, lParam);
     }
@@ -1658,8 +1712,27 @@ static HRESULT get_inproc_class_object(H
         APARTMENT *apt = COM_CurrentApt();
         if (apt->multi_threaded)
         {
-            FIXME("should create object %s in single-threaded apartment\n",
-                debugstr_guid(rclsid));
+            /* try to find an STA */
+            APARTMENT *host_apt = apartment_findfromtype(FALSE);
+            if (!host_apt)
+                FIXME("create a host apartment for apartment-threaded object %s\n", debugstr_guid(rclsid));
+            if (host_apt)
+            {
+                struct host_object_params params;
+                HWND hwnd = apartment_getwindow(host_apt);
+
+                params.hkeydll = hkeydll;
+                params.clsid = *rclsid;
+                params.iid = *riid;
+                hr = CreateStreamOnHGlobal(NULL, TRUE, &params.stream);
+                if (FAILED(hr))
+                    return hr;
+                hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)&params);
+                if (SUCCEEDED(hr))
+                    hr = CoUnmarshalInterface(params.stream, riid, ppv);
+                IStream_Release(params.stream);
+                return hr;
+            }
         }
     }
     /* "Free" */
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 4d27bab..ac9243c 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -246,6 +246,7 @@ void apartment_joinmta(void);
 
 /* DCOM messages used by the apartment window (not compatible with native) */
 #define DM_EXECUTERPC   (WM_USER + 0) /* WPARAM = 0, LPARAM = (struct dispatch_params *) */
+#define DM_HOSTOBJECT   (WM_USER + 1) /* WPARAM = 0, LPARAM = (struct host_object_params *) */
 
 /*
  * Per-thread values are stored in the TEB on offset 0xF80,




More information about the wine-cvs mailing list