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 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, ¶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)
|
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, ¶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" */
|
/* "Free" */
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue