Robert Shearman : ole32:
When marshaling a proxy make sure to maintain an external
Alexandre Julliard
julliard at wine.codeweavers.com
Thu Jun 29 08:32:03 CDT 2006
Module: wine
Branch: refs/heads/master
Commit: 2f0e714a2779b4ccca397cad67835afe64b94cfa
URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=2f0e714a2779b4ccca397cad67835afe64b94cfa
Author: Robert Shearman <rob at codeweavers.com>
Date: Wed Jun 28 21:25:14 2006 +0100
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.
---
dlls/ole32/marshal.c | 44 +++++++++++++++++++++++++++++++++++++++++---
dlls/ole32/tests/marshal.c | 38 ++++++++++++++++++++++++++++++--------
2 files changed, 71 insertions(+), 11 deletions(-)
diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c
index 12e886d..152647b 100644
--- a/dlls/ole32/marshal.c
+++ b/dlls/ole32/marshal.c
@@ -379,11 +379,49 @@ static HRESULT WINAPI Proxy_MarshalInter
if (SUCCEEDED(hr))
{
STDOBJREF stdobjref = ifproxy->stdobjref;
- /* FIXME: optimization - share out proxy's public references if possible
+ ULONG cPublicRefs = ifproxy->refs;
+ ULONG cPublicRefsOld;
+
+ /* 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 */
+ 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);
+ }
+ }
- hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
+ 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
{
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c
index 24f9268..102be87 100644
--- a/dlls/ole32/tests/marshal.c
+++ b/dlls/ole32/tests/marshal.c
@@ -434,6 +434,10 @@ static void test_interthread_marshal_and
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_unmar
IUnknown *pProxy2 = NULL;
DWORD tid;
HANDLE thread;
+ int i;
cLocks = 0;
@@ -465,14 +470,26 @@ static void test_proxy_marshal_and_unmar
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_unmar
* the above can only really be tested by looking in +ole traces
*/
- ok_more_than_one_lock();
-
- IUnknown_Release(pProxy);
+ IUnknown_Release(pProxy2);
- ok_more_than_one_lock();
+ /* 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);
+ IUnknown_Release(pProxy2);
+ }
ok_no_locks();
+ IStream_Release(pStream);
+
end_host_object(tid, thread);
}
More information about the wine-cvs
mailing list