From 857a6d1f63001794ad6370abeab6f610b37f6a90 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Wed, 1 Mar 2006 12:18:14 +0000 Subject: [PATCH] ole: Fix marshaling of proxies for interfaces that haven't already been unmarshaled. --- dlls/ole32/marshal.c | 56 +++++++++++++++++++++++++++------- dlls/ole32/tests/marshal.c | 61 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 106 insertions(+), 11 deletions(-) diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index ef3df6e4bbf..aebdba13e6b 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -366,25 +366,59 @@ static HRESULT WINAPI Proxy_MarshalInterface( 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 */ - 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); + 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); + + 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 10c690c6fea..3de88a937ec 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -472,6 +472,66 @@ static void test_proxy_marshal_and_unmarshal(void) 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();