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

single-threaded apartment if executing in a multi-threaded apartment,
if one exists.
This commit is contained in:
Robert Shearman 2006-08-26 11:42:40 +01:00 committed by Alexandre Julliard
parent c1eb2c7003
commit 619ba90dbe
2 changed files with 76 additions and 2 deletions

View File

@ -82,6 +82,7 @@ HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk); static HRESULT COM_GetRegisteredClassObject(REFCLSID rclsid, DWORD dwClsContext, LPUNKNOWN* ppUnk);
static void COM_RevokeAllClasses(void); 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 APARTMENT *MTA; /* protected by csApartment */
static struct list apts = LIST_INIT( apts ); /* protected by csApartment */ static struct list apts = LIST_INIT( apts ); /* protected by csApartment */
@ -427,6 +428,57 @@ APARTMENT *apartment_findfromtid(DWORD tid)
return result; 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) static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{ {
switch (msg) switch (msg)
@ -434,6 +486,8 @@ static LRESULT CALLBACK apartment_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LP
case DM_EXECUTERPC: case DM_EXECUTERPC:
RPC_ExecuteCall((struct dispatch_params *)lParam); RPC_ExecuteCall((struct dispatch_params *)lParam);
return 0; return 0;
case DM_HOSTOBJECT:
return apartment_hostobject((const struct host_object_params *)lParam);
default: default:
return DefWindowProcW(hWnd, msg, wParam, lParam); return DefWindowProcW(hWnd, msg, wParam, lParam);
} }
@ -1658,8 +1712,27 @@ static HRESULT get_inproc_class_object(HKEY hkeydll, REFCLSID rclsid, REFIID rii
APARTMENT *apt = COM_CurrentApt(); APARTMENT *apt = COM_CurrentApt();
if (apt->multi_threaded) if (apt->multi_threaded)
{ {
FIXME("should create object %s in single-threaded apartment\n", /* try to find an STA */
debugstr_guid(rclsid)); 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" */ /* "Free" */

View File

@ -246,6 +246,7 @@ void apartment_joinmta(void);
/* DCOM messages used by the apartment window (not compatible with native) */ /* 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_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, * Per-thread values are stored in the TEB on offset 0xF80,