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:
parent
c1eb2c7003
commit
619ba90dbe
|
@ -82,6 +82,7 @@ HINSTANCE OLE32_hInstance = 0; /* FIXME: make static ... */
|
|||
|
||||
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 tid)
|
|||
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_wndproc(HWND hWnd, UINT msg, WPARAM wParam, LP
|
|||
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(HKEY hkeydll, REFCLSID rclsid, REFIID rii
|
|||
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" */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue