From 327100fef98b2259842e8df4a7a1ebbd7e61ce01 Mon Sep 17 00:00:00 2001 From: Huw Davies Date: Tue, 13 Oct 2015 14:49:15 +0100 Subject: [PATCH] ole32: Don't block inside CoDisconnectObject. This may be called inside a COM call to the object. Signed-off-by: Huw Davies Signed-off-by: Alexandre Julliard --- dlls/ole32/compobj.c | 1 + dlls/ole32/compobj_private.h | 4 +++- dlls/ole32/rpc.c | 4 ++-- dlls/ole32/stubmanager.c | 19 ++++++++++++++++++- 4 files changed, 24 insertions(+), 4 deletions(-) diff --git a/dlls/ole32/compobj.c b/dlls/ole32/compobj.c index 0d0459a13c6..82904a8e1f5 100644 --- a/dlls/ole32/compobj.c +++ b/dlls/ole32/compobj.c @@ -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); diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index b2cf92ed244..7ceee2ca579 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -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; diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index 0797784f6c3..e8bf9bff3d8 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -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); } diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index fa9a70422d1..a7d00c501e0 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -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) {