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

This commit is contained in:
Robert Shearman 2006-03-01 12:18:14 +00:00 committed by Alexandre Julliard
parent 269909f53e
commit 857a6d1f63
2 changed files with 106 additions and 11 deletions

View File

@ -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;
}

View File

@ -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();