Module: wine Branch: refs/heads/master Commit: 2f0e714a2779b4ccca397cad67835afe64b94cfa URL: http://source.winehq.org/git/?p=wine.git;a=commit;h=2f0e714a2779b4ccca397cad...
Author: Robert Shearman rob@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); }