Huw Davies : ole32: Don't block inside CoDisconnectObject.

Alexandre Julliard julliard at wine.codeweavers.com
Wed Oct 14 11:12:49 CDT 2015


Module: wine
Branch: master
Commit: 327100fef98b2259842e8df4a7a1ebbd7e61ce01
URL:    http://source.winehq.org/git/wine.git/?a=commit;h=327100fef98b2259842e8df4a7a1ebbd7e61ce01

Author: Huw Davies <huw at codeweavers.com>
Date:   Tue Oct 13 14:49:15 2015 +0100

ole32: Don't block inside CoDisconnectObject.

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

Signed-off-by: Huw Davies <huw at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 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)
 {




More information about the wine-cvs mailing list