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))
|
if (SUCCEEDED(hr))
|
||||||
{
|
{
|
||||||
STDOBJREF stdobjref = ifproxy->stdobjref;
|
STDOBJREF stdobjref = ifproxy->stdobjref;
|
||||||
/* FIXME: optimization - share out proxy's public references if possible
|
ULONG cPublicRefs = ifproxy->refs;
|
||||||
* instead of making new proxy do a roundtrip through the server */
|
ULONG cPublicRefsOld;
|
||||||
stdobjref.cPublicRefs = 0; /* InterlockedDecrement(&This->stdobjref.cPublicRefs) >= 0 ? 1 : 0 */
|
|
||||||
|
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -434,6 +434,10 @@ static void test_interthread_marshal_and_unmarshal(void)
|
||||||
end_host_object(tid, thread);
|
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 */
|
/* tests success case of an interthread marshal and then marshaling the proxy */
|
||||||
static void test_proxy_marshal_and_unmarshal(void)
|
static void test_proxy_marshal_and_unmarshal(void)
|
||||||
{
|
{
|
||||||
|
@ -443,6 +447,7 @@ static void test_proxy_marshal_and_unmarshal(void)
|
||||||
IUnknown *pProxy2 = NULL;
|
IUnknown *pProxy2 = NULL;
|
||||||
DWORD tid;
|
DWORD tid;
|
||||||
HANDLE thread;
|
HANDLE thread;
|
||||||
|
int i;
|
||||||
|
|
||||||
cLocks = 0;
|
cLocks = 0;
|
||||||
|
|
||||||
|
@ -465,14 +470,26 @@ static void test_proxy_marshal_and_unmarshal(void)
|
||||||
|
|
||||||
ok_more_than_one_lock();
|
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);
|
IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
|
||||||
/* unmarshal the second proxy to the object */
|
|
||||||
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
|
hr = CoUnmarshalInterface(pStream, &IID_IClassFactory, (void **)&pProxy2);
|
||||||
ok_ole_success(hr, CoUnmarshalInterface);
|
ok_ole_success(hr, CoUnmarshalInterface);
|
||||||
IStream_Release(pStream);
|
|
||||||
|
ok_more_than_one_lock();
|
||||||
|
|
||||||
/* now the proxies should be as follows:
|
/* now the proxies should be as follows:
|
||||||
* pProxy -> &Test_ClassFactory
|
|
||||||
* pProxy2 -> &Test_ClassFactory
|
* pProxy2 -> &Test_ClassFactory
|
||||||
* they should NOT be as follows:
|
* they should NOT be as follows:
|
||||||
* pProxy -> &Test_ClassFactory
|
* 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
|
* 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);
|
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();
|
ok_no_locks();
|
||||||
|
|
||||||
|
IStream_Release(pStream);
|
||||||
|
|
||||||
end_host_object(tid, thread);
|
end_host_object(tid, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue