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:
Rob Shearman 2008-04-28 19:42:51 +01:00 committed by Alexandre Julliard
parent 4cb5c3b7d6
commit 8580198dc8
5 changed files with 37 additions and 24 deletions

View File

@ -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);
}

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);