ole32: Don't block inside CoDisconnectObject.

This may be called inside a COM call to the object.

Signed-off-by: Huw Davies <huw@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Huw Davies 2015-10-13 14:49:15 +01:00 committed by Alexandre Julliard
parent 35571a7254
commit 327100fef9
4 changed files with 24 additions and 4 deletions

View File

@ -2042,6 +2042,7 @@ HRESULT WINAPI CoDisconnectObject( LPUNKNOWN lpUnk, DWORD reserved )
manager = get_stub_manager_from_object(apt, lpUnk, FALSE);
if (manager) {
stub_manager_disconnect(manager);
/* Release stub manager twice, to remove the apartment reference. */
stub_manager_int_release(manager);
stub_manager_int_release(manager);

View File

@ -107,6 +107,7 @@ struct stub_manager
*/
ULONG norm_refs; /* refcount of normal marshals (CS lock) */
BOOL disconnected; /* CoDisconnectObject has been called (CS lock) */
};
/* imported interface proxy */
@ -195,6 +196,7 @@ struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, IUnknown *obje
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid) DECLSPEC_HIDDEN;
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid) DECLSPEC_HIDDEN;
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak) DECLSPEC_HIDDEN;
void stub_manager_disconnect(struct stub_manager *m) DECLSPEC_HIDDEN;
HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **manager, IRpcStubBuffer **stub,
IRpcChannelBuffer **chan, IID *iid, IUnknown **iface) DECLSPEC_HIDDEN;
HRESULT start_apartment_remote_unknown(void) DECLSPEC_HIDDEN;
@ -213,7 +215,7 @@ HRESULT RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid,
HRESULT RPC_CreateServerChannel(DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan) DECLSPEC_HIDDEN;
void RPC_ExecuteCall(struct dispatch_params *params) DECLSPEC_HIDDEN;
HRESULT RPC_RegisterInterface(REFIID riid) DECLSPEC_HIDDEN;
void RPC_UnregisterInterface(REFIID riid) DECLSPEC_HIDDEN;
void RPC_UnregisterInterface(REFIID riid, BOOL wait) DECLSPEC_HIDDEN;
HRESULT RPC_StartLocalServer(REFCLSID clsid, IStream *stream, BOOL multi_use, void **registration) DECLSPEC_HIDDEN;
void RPC_StopLocalServer(void *registration) DECLSPEC_HIDDEN;
HRESULT RPC_GetLocalClassObject(REFCLSID rclsid, REFIID iid, LPVOID *ppv) DECLSPEC_HIDDEN;

View File

@ -1581,7 +1581,7 @@ HRESULT RPC_RegisterInterface(REFIID riid)
}
/* stub unregistration */
void RPC_UnregisterInterface(REFIID riid)
void RPC_UnregisterInterface(REFIID riid, BOOL wait)
{
struct registered_if *rif;
EnterCriticalSection(&csRegIf);
@ -1591,7 +1591,7 @@ void RPC_UnregisterInterface(REFIID riid)
{
if (!--rif->refs)
{
RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, TRUE);
RpcServerUnregisterIf((RPC_IF_HANDLE)&rif->If, NULL, wait);
list_remove(&rif->entry);
HeapFree(GetProcessHeap(), 0, rif);
}

View File

@ -123,7 +123,8 @@ static void stub_manager_delete_ifstub(struct stub_manager *m, struct ifstub *if
list_remove(&ifstub->entry);
RPC_UnregisterInterface(&ifstub->iid);
if (!m->disconnected)
RPC_UnregisterInterface(&ifstub->iid, TRUE);
if (ifstub->stubbuffer) IRpcStubBuffer_Release(ifstub->stubbuffer);
IUnknown_Release(ifstub->iface);
@ -223,6 +224,7 @@ static struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
* the marshalled ifptr.
*/
sm->extrefs = 0;
sm->disconnected = FALSE;
hres = IUnknown_QueryInterface(object, &IID_IExternalConnection, (void**)&sm->extern_conn);
if(FAILED(hres))
@ -238,6 +240,21 @@ static struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
return sm;
}
void stub_manager_disconnect(struct stub_manager *m)
{
struct ifstub *ifstub;
EnterCriticalSection(&m->lock);
if (!m->disconnected)
{
LIST_FOR_EACH_ENTRY(ifstub, &m->ifstubs, struct ifstub, entry)
RPC_UnregisterInterface(&ifstub->iid, FALSE);
m->disconnected = TRUE;
}
LeaveCriticalSection(&m->lock);
}
/* caller must remove stub manager from apartment prior to calling this function */
static void stub_manager_delete(struct stub_manager *m)
{