Commit cb9c40a8 authored by Rob Shearman's avatar Rob Shearman Committed by Alexandre Julliard

ole32: Add the external references that the server gave to us to any existing ifproxy,

so that the right external reference count is released when the proxy is destroyed. Protect all changes to refs in the ifproxy using interlocked functions and update the thread-safety documentation.
parent 723592cf
......@@ -112,7 +112,7 @@ struct ifproxy
STDOBJREF stdobjref; /* marshal data that represents this object (RO) */
IID iid; /* interface ID (RO) */
LPRPCPROXYBUFFER proxy; /* interface proxy (RO) */
DWORD refs; /* imported (public) references (MUTEX parent->remoting_mutex) */
ULONG refs; /* imported (public) references (LOCK) */
IRpcChannelBuffer *chan; /* channel to object (CS parent->cs) */
};
......
......@@ -498,7 +498,7 @@ static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
rif.cPrivateRefs = 0;
hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
if (hr == S_OK && hrref == S_OK)
This->refs += NORMALEXTREFS;
InterlockedExchangeAdd((LONG *)&This->refs, NORMALEXTREFS);
else
ERR("IRemUnknown_RemAddRef returned with 0x%08x, hrref = 0x%08x\n", hr, hrref);
}
......@@ -511,6 +511,7 @@ static HRESULT ifproxy_get_public_ref(struct ifproxy * This)
static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
{
HRESULT hr = S_OK;
LONG public_refs;
if (WAIT_OBJECT_0 != WaitForSingleObject(This->parent->remoting_mutex, INFINITE))
{
......@@ -518,22 +519,23 @@ static HRESULT ifproxy_release_public_refs(struct ifproxy * This)
return E_UNEXPECTED;
}
if (This->refs > 0)
public_refs = This->refs;
if (public_refs > 0)
{
IRemUnknown *remunk = NULL;
TRACE("releasing %d refs\n", This->refs);
TRACE("releasing %d refs\n", public_refs);
hr = proxy_manager_get_remunknown(This->parent, &remunk);
if (hr == S_OK)
{
REMINTERFACEREF rif;
rif.ipid = This->stdobjref.ipid;
rif.cPublicRefs = This->refs;
rif.cPublicRefs = public_refs;
rif.cPrivateRefs = 0;
hr = IRemUnknown_RemRelease(remunk, 1, &rif);
if (hr == S_OK)
This->refs = 0;
InterlockedExchangeAdd((LONG *)&This->refs, -public_refs);
else if (hr == RPC_E_DISCONNECTED)
WARN("couldn't release references because object was "
"disconnected: oxid = %s, oid = %s\n",
......@@ -751,7 +753,7 @@ static HRESULT proxy_manager_create_ifproxy(
ifproxy->parent = This;
ifproxy->stdobjref = *stdobjref;
ifproxy->iid = *riid;
ifproxy->refs = stdobjref->cPublicRefs;
ifproxy->refs = 0;
ifproxy->proxy = NULL;
assert(channel);
......@@ -789,10 +791,6 @@ static HRESULT proxy_manager_create_ifproxy(
hr = IRpcProxyBuffer_Connect(ifproxy->proxy, ifproxy->chan);
}
/* get at least one external reference to the object to keep it alive */
if (hr == S_OK)
hr = ifproxy_get_public_ref(ifproxy);
if (hr == S_OK)
{
EnterCriticalSection(&This->cs);
......@@ -1136,6 +1134,15 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt,
IUnknown_AddRef((IUnknown *)ifproxy->iface);
if (hr == S_OK)
{
InterlockedExchangeAdd((LONG *)&ifproxy->refs, stdobjref->cPublicRefs);
/* get at least one external reference to the object to keep it alive */
hr = ifproxy_get_public_ref(ifproxy);
if (FAILED(hr))
ifproxy_destroy(ifproxy);
}
if (hr == S_OK)
*object = ifproxy->iface;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment