[PATCH 2/4] ole32: Don't block inside CoDisconnectObject.
Huw Davies
huw at codeweavers.com
Tue Oct 13 08:49:15 CDT 2015
This may be called inside a COM call to the object.
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
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 0d0459a..82904a8 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 b2cf92e..7ceee2c 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 0797784..e8bf9bf 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 fa9a704..a7d00c5 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)
{
--
1.8.0
More information about the wine-patches
mailing list