ole32: When marshaling a proxy make sure to maintain an external
reference on the stub object so that the first proxy can be released. Implement external refcount sharing between a proxy and the marshaled proxy. Extend the marshaling of a proxy test to show that an external reference is always kept on the stub object.
This commit is contained in:
parent
723aceb20f
commit
2f0e714a27
|
@ -379,11 +379,49 @@ static HRESULT WINAPI Proxy_MarshalInterface(
|
|||
if (SUCCEEDED(hr))
|
||||
{
|
||||
STDOBJREF stdobjref = ifproxy->stdobjref;
|
||||
/* FIXME: optimization - share out proxy's public references if possible
|
||||
* instead of making new proxy do a roundtrip through the server */
|
||||
stdobjref.cPublicRefs = 0; /* InterlockedDecrement(&This->stdobjref.cPublicRefs) >= 0 ? 1 : 0 */
|
||||
ULONG cPublicRefs = ifproxy->refs;
|
||||
ULONG cPublicRefsOld;
|
||||
|
||||
hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
|
||||
/* optimization - share out proxy's public references if possible
|
||||
* instead of making new proxy do a roundtrip through the server */
|
||||
do
|
||||
{
|
||||
ULONG cPublicRefsNew;
|
||||
cPublicRefsOld = cPublicRefs;
|
||||
stdobjref.cPublicRefs = cPublicRefs / 2;
|
||||
cPublicRefsNew = cPublicRefs - stdobjref.cPublicRefs;
|
||||
cPublicRefs = InterlockedCompareExchange(
|
||||
(LONG *)&ifproxy->refs, cPublicRefsNew, cPublicRefsOld);
|
||||
} while (cPublicRefs != cPublicRefsOld);
|
||||
|
||||
if (!stdobjref.cPublicRefs)
|
||||
{
|
||||
IRemUnknown *remunk;
|
||||
hr = proxy_manager_get_remunknown(This, &remunk);
|
||||
if (hr == S_OK)
|
||||
{
|
||||
HRESULT hrref = S_OK;
|
||||
REMINTERFACEREF rif;
|
||||
rif.ipid = ifproxy->stdobjref.ipid;
|
||||
rif.cPublicRefs = NORMALEXTREFS;
|
||||
rif.cPrivateRefs = 0;
|
||||
hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref);
|
||||
if (hr == S_OK && hrref == S_OK)
|
||||
stdobjref.cPublicRefs = rif.cPublicRefs;
|
||||
else
|
||||
ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref);
|
||||
}
|
||||
}
|
||||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
TRACE("writing stdobjref:\n\tflags = %04lx\n\tcPublicRefs = %ld\n\toxid = %s\n\toid = %s\n\tipid = %s\n",
|
||||
stdobjref.flags, stdobjref.cPublicRefs,
|
||||
wine_dbgstr_longlong(stdobjref.oxid),
|
||||
wine_dbgstr_longlong(stdobjref.oid),
|
||||
debugstr_guid(&stdobjref.ipid));
|
||||
hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
@ -434,6 +434,10 @@ static void test_interthread_marshal_and_unmarshal(void)
|
|||
end_host_object(tid, thread);
|
||||
}
|
||||
|
||||
/* the number of external references that Wine's proxy manager normally gives
|
||||
* out, so we can test the border case of running out of references */
|
||||
#define NORMALEXTREFS 5
|
||||
|
||||
/* tests success case of an interthread marshal and then marshaling the proxy */
|
||||
static void test_proxy_marshal_and_unmarshal(void)
|
||||
{
|
||||
|
@ -443,6 +447,7 @@ static void test_proxy_marshal_and_unmarshal(void)
|
|||
IUnknown *pProxy2 = NULL;
|
||||
DWORD tid;
|
||||
HANDLE thread;
|
||||
int i;
|
||||
|
||||
cLocks = 0;
|
||||
|
||||
|
@ -465,14 +470,26 @@ static void test_proxy_marshal_and_unmarshal(void)
|
|||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
/* marshal 5 more times to exhaust the normal external references of 5 */
|
||||
for (i = 0; i < NORMALEXTREFS; i++)
|
||||
{
|
||||
hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
|
||||
ok_ole_success(hr, CoMarshalInterface);
|
||||
}
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
/* release the original proxy to test that we successfully keep the
|
||||
* original object alive */
|
||||
IUnknown_Release(pProxy);
|
||||
|
||||
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||
/* unmarshal the second proxy to the object */
|
||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
|
||||
ok_ole_success(hr, CoUnmarshalInterface);
|
||||
IStream_Release(pStream);
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
/* now the proxies should be as follows:
|
||||
* pProxy -> &Test_ClassFactory
|
||||
* pProxy2 -> &Test_ClassFactory
|
||||
* they should NOT be as follows:
|
||||
* pProxy -> &Test_ClassFactory
|
||||
|
@ -480,16 +497,21 @@ static void test_proxy_marshal_and_unmarshal(void)
|
|||
* the above can only really be tested by looking in +ole traces
|
||||
*/
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
IUnknown_Release(pProxy);
|
||||
|
||||
ok_more_than_one_lock();
|
||||
|
||||
IUnknown_Release(pProxy2);
|
||||
|
||||
/* unmarshal all of the proxies to check that the object stub still exists */
|
||||
for (i = 0; i < NORMALEXTREFS; i++)
|
||||
{
|
||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
|
||||
ok_ole_success(hr, CoUnmarshalInterface);
|
||||
|
||||
IUnknown_Release(pProxy2);
|
||||
}
|
||||
|
||||
ok_no_locks();
|
||||
|
||||
IStream_Release(pStream);
|
||||
|
||||
end_host_object(tid, thread);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue