mirror of
https://github.com/reactos/wine.git
synced 2024-11-26 13:10:28 +00:00
ole: Fix marshaling of proxies for interfaces that haven't already been unmarshaled.
This commit is contained in:
parent
269909f53e
commit
857a6d1f63
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user