Module: wine Branch: master Commit: 619ba90dbecaca7b4bc360b38bd7ba45f5b82546 URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=619ba90dbecaca7b4bc360b3...
Author: Robert Shearman rob@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, ¶ms->clsid, ¶ms->iid, (void **)&object); + if (FAILED(hr)) + return hr; + + hr = CoMarshalInterface(params->stream, ¶ms->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, ¶ms.stream); + if (FAILED(hr)) + return hr; + hr = SendMessageW(hwnd, DM_HOSTOBJECT, 0, (LPARAM)¶ms); + 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,