ole32: Keep track of the number of weak references to an object.
This is so that an object will only be released when a weak-reference is used after the last weak reference has been released (either by CoReleaseMarshalData or CoUnmarshalInterface + Release).
This commit is contained in:
parent
4cb5c3b7d6
commit
8580198dc8
|
@ -2652,9 +2652,9 @@ HRESULT WINAPI CoLockObjectExternal(
|
|||
if (stubmgr)
|
||||
{
|
||||
if (fLock)
|
||||
stub_manager_ext_addref(stubmgr, 1);
|
||||
stub_manager_ext_addref(stubmgr, 1, FALSE);
|
||||
else
|
||||
stub_manager_ext_release(stubmgr, 1, fLastUnlockReleases);
|
||||
stub_manager_ext_release(stubmgr, 1, FALSE, fLastUnlockReleases);
|
||||
|
||||
stub_manager_int_release(stubmgr);
|
||||
|
||||
|
@ -2666,7 +2666,7 @@ HRESULT WINAPI CoLockObjectExternal(
|
|||
|
||||
if (stubmgr)
|
||||
{
|
||||
stub_manager_ext_addref(stubmgr, 1);
|
||||
stub_manager_ext_addref(stubmgr, 1, FALSE);
|
||||
stub_manager_int_release(stubmgr);
|
||||
}
|
||||
|
||||
|
|
|
@ -92,6 +92,7 @@ struct stub_manager
|
|||
|
||||
ULONG extrefs; /* number of 'external' references (CS lock) */
|
||||
ULONG refs; /* internal reference count (CS apt->cs) */
|
||||
ULONG weakrefs; /* number of weak references (CS lock) */
|
||||
OID oid; /* apartment-scoped unique identifier (RO) */
|
||||
IUnknown *object; /* the object we are managing the stub for (RO) */
|
||||
ULONG next_ipid; /* currently unused (LOCK) */
|
||||
|
@ -201,15 +202,15 @@ HRESULT FTMarshalCF_Create(REFIID riid, LPVOID *ppv);
|
|||
ULONG stub_manager_int_addref(struct stub_manager *This);
|
||||
ULONG stub_manager_int_release(struct stub_manager *This);
|
||||
struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object);
|
||||
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs);
|
||||
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL last_unlock_releases);
|
||||
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak);
|
||||
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases);
|
||||
struct ifstub *stub_manager_new_ifstub(struct stub_manager *m, IRpcStubBuffer *sb, IUnknown *iptr, REFIID iid, MSHLFLAGS flags);
|
||||
struct ifstub *stub_manager_find_ifstub(struct stub_manager *m, REFIID iid, MSHLFLAGS flags);
|
||||
struct stub_manager *get_stub_manager(APARTMENT *apt, OID oid);
|
||||
struct stub_manager *get_stub_manager_from_object(APARTMENT *apt, void *object);
|
||||
BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid);
|
||||
BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid);
|
||||
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid);
|
||||
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak);
|
||||
HRESULT ipid_to_stub_manager(const IPID *ipid, APARTMENT **stub_apt, struct stub_manager **stubmgr_ret);
|
||||
HRESULT ipid_get_dispatch_params(const IPID *ipid, APARTMENT **stub_apt, IRpcStubBuffer **stub, IRpcChannelBuffer **chan, IID *iid, IUnknown **iface);
|
||||
HRESULT start_apartment_remote_unknown(void);
|
||||
|
|
|
@ -45,9 +45,12 @@ extern const CLSID CLSID_DfMarshal;
|
|||
/* number of refs given out for normal marshaling */
|
||||
#define NORMALEXTREFS 5
|
||||
|
||||
|
||||
/* private flag indicating that the object was marshaled as table-weak */
|
||||
#define SORFP_TABLEWEAK SORF_OXRES1
|
||||
/* private flag indicating that the caller does not want to notify the stub
|
||||
* when the proxy disconnects or is destroyed */
|
||||
#define SORFP_NOLIFETIMEMGMT SORF_OXRES1
|
||||
#define SORFP_NOLIFETIMEMGMT SORF_OXRES2
|
||||
|
||||
static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
|
||||
MSHCTX dest_context, void *dest_context_data,
|
||||
|
@ -131,10 +134,11 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno
|
|||
}
|
||||
}
|
||||
|
||||
stdobjref->flags = SORF_NULL;
|
||||
if (mshlflags & MSHLFLAGS_TABLEWEAK)
|
||||
stdobjref->flags |= SORFP_TABLEWEAK;
|
||||
if (mshlflags & MSHLFLAGS_NOPING)
|
||||
stdobjref->flags = SORF_NOPING;
|
||||
else
|
||||
stdobjref->flags = SORF_NULL;
|
||||
stdobjref->flags |= SORF_NOPING;
|
||||
|
||||
if ((manager = get_stub_manager_from_object(apt, object)))
|
||||
TRACE("registering new ifstub on pre-existing manager\n");
|
||||
|
@ -167,20 +171,22 @@ HRESULT marshal_object(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkno
|
|||
stub_manager_int_release(manager);
|
||||
/* destroy the stub manager if it has no ifstubs by releasing
|
||||
* zero external references */
|
||||
stub_manager_ext_release(manager, 0, TRUE);
|
||||
stub_manager_ext_release(manager, 0, FALSE, TRUE);
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
if (!tablemarshal)
|
||||
{
|
||||
stdobjref->cPublicRefs = NORMALEXTREFS;
|
||||
stub_manager_ext_addref(manager, stdobjref->cPublicRefs);
|
||||
stub_manager_ext_addref(manager, stdobjref->cPublicRefs, FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
stdobjref->cPublicRefs = 0;
|
||||
if (mshlflags & MSHLFLAGS_TABLESTRONG)
|
||||
stub_manager_ext_addref(manager, 1);
|
||||
stub_manager_ext_addref(manager, 1, FALSE);
|
||||
else
|
||||
stub_manager_ext_addref(manager, 0, TRUE);
|
||||
}
|
||||
|
||||
/* FIXME: check return value */
|
||||
|
@ -1330,7 +1336,7 @@ StdMarshalImpl_UnmarshalInterface(LPMARSHAL iface, IStream *pStm, REFIID riid, v
|
|||
|
||||
/* unref the ifstub. FIXME: only do this on success? */
|
||||
if (!stub_manager_is_table_marshaled(stubmgr, &stdobjref.ipid))
|
||||
stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, TRUE);
|
||||
stub_manager_ext_release(stubmgr, stdobjref.cPublicRefs, stdobjref.flags & SORFP_TABLEWEAK, TRUE);
|
||||
|
||||
stub_manager_int_release(stubmgr);
|
||||
return hres;
|
||||
|
@ -1407,7 +1413,7 @@ StdMarshalImpl_ReleaseMarshalData(LPMARSHAL iface, IStream *pStm)
|
|||
return RPC_E_INVALID_OBJREF;
|
||||
}
|
||||
|
||||
stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid);
|
||||
stub_manager_release_marshal_data(stubmgr, stdobjref.cPublicRefs, &stdobjref.ipid, stdobjref.flags & SORFP_TABLEWEAK);
|
||||
|
||||
stub_manager_int_release(stubmgr);
|
||||
apartment_release(apt);
|
||||
|
|
|
@ -69,6 +69,7 @@ struct stub_manager *new_stub_manager(APARTMENT *apt, IUnknown *object)
|
|||
/* start off with 2 references because the stub is in the apartment
|
||||
* and the caller will also hold a reference */
|
||||
sm->refs = 2;
|
||||
sm->weakrefs = 0;
|
||||
|
||||
sm->oxid_info.dwPid = GetCurrentProcessId();
|
||||
sm->oxid_info.dwTid = GetCurrentThreadId();
|
||||
|
@ -252,16 +253,19 @@ ULONG stub_manager_int_release(struct stub_manager *This)
|
|||
}
|
||||
|
||||
/* add some external references (ie from a client that unmarshaled an ifptr) */
|
||||
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs)
|
||||
ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL tableweak)
|
||||
{
|
||||
ULONG rc;
|
||||
|
||||
EnterCriticalSection(&m->lock);
|
||||
|
||||
|
||||
/* make sure we don't overflow extrefs */
|
||||
refs = min(refs, (ULONG_MAX-1 - m->extrefs));
|
||||
rc = (m->extrefs += refs);
|
||||
|
||||
if (tableweak)
|
||||
rc += ++m->weakrefs;
|
||||
|
||||
LeaveCriticalSection(&m->lock);
|
||||
|
||||
TRACE("added %u refs to %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
|
||||
|
@ -270,7 +274,7 @@ ULONG stub_manager_ext_addref(struct stub_manager *m, ULONG refs)
|
|||
}
|
||||
|
||||
/* remove some external references */
|
||||
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL last_unlock_releases)
|
||||
ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases)
|
||||
{
|
||||
ULONG rc;
|
||||
|
||||
|
@ -280,6 +284,9 @@ ULONG stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL last_unl
|
|||
refs = min(refs, m->extrefs);
|
||||
rc = (m->extrefs -= refs);
|
||||
|
||||
if (tableweak)
|
||||
rc += --m->weakrefs;
|
||||
|
||||
LeaveCriticalSection(&m->lock);
|
||||
|
||||
TRACE("removed %u refs from %p (oid %s), rc is now %u\n", refs, m, wine_dbgstr_longlong(m->oid), rc);
|
||||
|
@ -534,7 +541,7 @@ BOOL stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid)
|
|||
}
|
||||
|
||||
/* handles refcounting for CoReleaseMarshalData */
|
||||
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid)
|
||||
void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak)
|
||||
{
|
||||
struct ifstub *ifstub;
|
||||
|
||||
|
@ -546,7 +553,7 @@ void stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const
|
|||
else if (ifstub->flags & MSHLFLAGS_TABLESTRONG)
|
||||
refs = 1;
|
||||
|
||||
stub_manager_ext_release(m, refs, TRUE);
|
||||
stub_manager_ext_release(m, refs, tableweak, TRUE);
|
||||
}
|
||||
|
||||
/* is an ifstub table marshaled? */
|
||||
|
@ -693,7 +700,7 @@ static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface,
|
|||
continue;
|
||||
}
|
||||
|
||||
stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs);
|
||||
stub_manager_ext_addref(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE);
|
||||
if (InterfaceRefs[i].cPrivateRefs)
|
||||
FIXME("Adding %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
|
||||
|
||||
|
@ -726,7 +733,7 @@ static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface,
|
|||
break;
|
||||
}
|
||||
|
||||
stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, TRUE);
|
||||
stub_manager_ext_release(stubmgr, InterfaceRefs[i].cPublicRefs, FALSE, TRUE);
|
||||
if (InterfaceRefs[i].cPrivateRefs)
|
||||
FIXME("Releasing %ld refs securely not implemented\n", InterfaceRefs[i].cPrivateRefs);
|
||||
|
||||
|
|
|
@ -701,9 +701,8 @@ static void test_ROT_multiple_entries(void)
|
|||
ok_ole_success(hr, IRunningObjectTable_Revoke);
|
||||
|
||||
hr = IRunningObjectTable_GetObject(pROT, pMoniker, &pObject);
|
||||
todo_wine
|
||||
ok_ole_success(hr, IRunningObjectTable_GetObject);
|
||||
if (pObject) IUnknown_Release(pObject);
|
||||
IUnknown_Release(pObject);
|
||||
|
||||
hr = IRunningObjectTable_Revoke(pROT, dwCookie2);
|
||||
ok_ole_success(hr, IRunningObjectTable_Revoke);
|
||||
|
|
Loading…
Reference in New Issue