Robert Shearman : ole: Fix marshaling of proxies for interfaces that haven' t already been unmarshaled.

Alexandre Julliard julliard at wine.codeweavers.com
Thu Mar 2 05:17:32 CST 2006


Module: wine
Branch: refs/heads/master
Commit: 857a6d1f63001794ad6370abeab6f610b37f6a90
URL:    http://source.winehq.org/git/?p=wine.git;a=commit;h=857a6d1f63001794ad6370abeab6f610b37f6a90

Author: Robert Shearman <rob at codeweavers.com>
Date:   Wed Mar  1 12:18:14 2006 +0000

ole: Fix marshaling of proxies for interfaces that haven't already been unmarshaled.

---

 dlls/ole32/marshal.c       |   54 ++++++++++++++++++++++++++++++++-------
 dlls/ole32/tests/marshal.c |   61 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 105 insertions(+), 10 deletions(-)

diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c
index ef3df6e..aebdba1 100644
--- a/dlls/ole32/marshal.c
+++ b/dlls/ole32/marshal.c
@@ -366,25 +366,59 @@ static HRESULT WINAPI Proxy_MarshalInter
     void* pvDestContext, DWORD mshlflags)
 {
     ICOM_THIS_MULTI(struct proxy_manager, lpVtblMarshal, iface);
-    ULONG res;
     HRESULT hr;
-    STDOBJREF stdobjref;
     struct ifproxy *ifproxy;
 
     TRACE("(...,%s,...)\n", debugstr_guid(riid));
 
     hr = proxy_manager_find_ifproxy(This, riid, &ifproxy);
-    if (FAILED(hr))
+    if (SUCCEEDED(hr))
     {
-        ERR("couldn't find proxy for interface %s, error 0x%08lx\n", debugstr_guid(riid), hr);
-        return 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 */
+
+        hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), NULL);
     }
+    else
+    {
+        /* we don't have the interface already unmarshaled so we have to
+         * request the object from the server */
+        IRemUnknown *remunk;
+        IPID *ipid;
+        REMQIRESULT *qiresults = NULL;
+        IID iid = *riid;
+
+        /* get the ipid of the first entry */
+        /* FIXME: should we implement ClientIdentity on the ifproxies instead
+         * of the proxy_manager so we use the correct ipid here? */
+        ipid = &LIST_ENTRY(list_head(&This->interfaces), struct ifproxy, entry)->stdobjref.ipid;
+
+        /* get IRemUnknown proxy so we can communicate with the remote object */
+        hr = proxy_manager_get_remunknown(This, &remunk);
 
-    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 */
-    hr = IStream_Write(pStm, &stdobjref, sizeof(stdobjref), &res);
+        if (hr == S_OK)
+        {
+            hr = IRemUnknown_RemQueryInterface(remunk, ipid, NORMALEXTREFS,
+                                               1, &iid, &qiresults);
+            if (SUCCEEDED(hr))
+            {
+                hr = IStream_Write(pStm, &qiresults->std, sizeof(qiresults->std), NULL);
+                if (FAILED(hr))
+                {
+                    REMINTERFACEREF rif;
+                    rif.ipid = qiresults->std.ipid;
+                    rif.cPublicRefs = qiresults->std.cPublicRefs;
+                    rif.cPrivateRefs = 0;
+                    IRemUnknown_RemRelease(remunk, 1, &rif);
+                }
+                CoTaskMemFree(qiresults);
+            }
+            else
+                ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr);
+        }
+    }
 
     return hr;
 }
diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c
index 10c690c..3de88a9 100644
--- a/dlls/ole32/tests/marshal.c
+++ b/dlls/ole32/tests/marshal.c
@@ -472,6 +472,66 @@ static void test_proxy_marshal_and_unmar
     end_host_object(tid, thread);
 }
 
+/* tests success case of an interthread marshal and then marshaling the proxy
+ * using an iid that hasn't previously been unmarshaled */
+static void test_proxy_marshal_and_unmarshal2(void)
+{
+    HRESULT hr;
+    IStream *pStream = NULL;
+    IUnknown *pProxy = NULL;
+    IUnknown *pProxy2 = NULL;
+    DWORD tid;
+    HANDLE thread;
+
+    cLocks = 0;
+
+    hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
+    ok_ole_success(hr, CreateStreamOnHGlobal);
+    tid = start_host_object(pStream, &IID_IUnknown, (IUnknown*)&Test_ClassFactory, MSHLFLAGS_NORMAL, &thread);
+
+    ok_more_than_one_lock();
+
+    IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
+    hr = CoUnmarshalInterface(pStream, &IID_IUnknown, (void **)&pProxy);
+    ok_ole_success(hr, CoUnmarshalInterface);
+
+    ok_more_than_one_lock();
+
+    IStream_Seek(pStream, ullZero, STREAM_SEEK_SET, NULL);
+    /* marshal the proxy */
+    hr = CoMarshalInterface(pStream, &IID_IClassFactory, pProxy, MSHCTX_INPROC, NULL, MSHLFLAGS_NORMAL);
+    ok_ole_success(hr, CoMarshalInterface);
+
+    ok_more_than_one_lock();
+
+    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);
+
+    /* now the proxies should be as follows:
+     *  pProxy -> &Test_ClassFactory
+     *  pProxy2 -> &Test_ClassFactory
+     * they should NOT be as follows:
+     *  pProxy -> &Test_ClassFactory
+     *  pProxy2 -> pProxy
+     * 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);
+
+    ok_no_locks();
+
+    end_host_object(tid, thread);
+}
+
 /* tests that stubs are released when the containing apartment is destroyed */
 static void test_marshal_stub_apartment_shutdown(void)
 {
@@ -1930,6 +1990,7 @@ START_TEST(marshal)
     test_marshal_and_unmarshal_invalid();
     test_interthread_marshal_and_unmarshal();
     test_proxy_marshal_and_unmarshal();
+    test_proxy_marshal_and_unmarshal2();
     test_marshal_stub_apartment_shutdown();
     test_marshal_proxy_apartment_shutdown();
     test_marshal_proxy_mta_apartment_shutdown();




More information about the wine-cvs mailing list