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:
parent
35571a7254
commit
327100fef9
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue