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