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:
Robert Shearman 2006-06-28 21:25:14 +01:00 committed by Alexandre Julliard
parent 723aceb20f
commit 2f0e714a27
2 changed files with 73 additions and 13 deletions

View File

@ -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
{

View File

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