From 3018974ce358c84f33ffc896493ddf30a2e30420 Mon Sep 17 00:00:00 2001 From: Robert Shearman Date: Wed, 26 Jan 2005 21:07:05 +0000 Subject: [PATCH] - Make proxy manager use IMultiQI instead of IInternalUnknown as tests show that IInternalUnknown isn't exposed. - Implement IMultiQI on top of IRemUnknown calls. - Silence some fixmes that occur during tests and don't give us any useful information. - Fix typo in class factory proxy that caused us to use the wrong offset into the CFProxy structure, causing us to not call the outer_unknown properly. --- dlls/ole32/compobj_private.h | 2 +- dlls/ole32/marshal.c | 201 ++++++++++++++++++++++++++--------- dlls/ole32/oleproxy.c | 2 +- dlls/ole32/rpc.c | 16 +-- dlls/ole32/stubmanager.c | 16 ++- dlls/ole32/tests/marshal.c | 2 +- 6 files changed, 173 insertions(+), 66 deletions(-) diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h index 6b7686bd791..69af30a7226 100644 --- a/dlls/ole32/compobj_private.h +++ b/dlls/ole32/compobj_private.h @@ -100,7 +100,7 @@ struct ifproxy /* imported object / proxy manager */ struct proxy_manager { - const IInternalUnknownVtbl *lpVtbl; + const IMultiQIVtbl *lpVtbl; struct apartment *parent; /* owning apartment (RO) */ struct list entry; /* entry in apartment (CS parent->cs) */ LPRPCCHANNELBUFFER chan; /* channel to object (CS cs) */ diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c index ca050700479..f7115908504 100644 --- a/dlls/ole32/marshal.c +++ b/dlls/ole32/marshal.c @@ -171,47 +171,30 @@ HRESULT register_ifstub(APARTMENT *apt, STDOBJREF *stdobjref, REFIID riid, IUnkn static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnknown **remunk); static void proxy_manager_destroy(struct proxy_manager * This); static HRESULT proxy_manager_find_ifproxy(struct proxy_manager * This, REFIID riid, struct ifproxy ** ifproxy_found); +static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv); -static HRESULT WINAPI ClientIdentity_QueryInterface(IInternalUnknown * iface, REFIID riid, void ** ppv) +static HRESULT WINAPI ClientIdentity_QueryInterface(IMultiQI * iface, REFIID riid, void ** ppv) { - struct proxy_manager * This = (struct proxy_manager *)iface; HRESULT hr; - struct ifproxy * ifproxy; + MULTI_QI mqi; TRACE("%s\n", debugstr_guid(riid)); - if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IInternalUnknown)) - { - *ppv = (void *)iface; - IInternalUnknown_AddRef(iface); - return S_OK; - } + mqi.pIID = riid; + hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi); + *ppv = (void *)mqi.pItf; - hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); - if (hr == S_OK) - { - *ppv = ifproxy->iface; - IUnknown_AddRef((IUnknown *)*ppv); - return S_OK; - } - - FIXME("interface not found %s\n", debugstr_guid(riid)); - - /* FIXME: call IRemUnknown::RemQueryInterface */ - - *ppv = NULL; - return E_NOINTERFACE; + return hr; } -static ULONG WINAPI ClientIdentity_AddRef(IInternalUnknown * iface) +static ULONG WINAPI ClientIdentity_AddRef(IMultiQI * iface) { struct proxy_manager * This = (struct proxy_manager *)iface; TRACE("%p - before %ld\n", iface, This->refs); return InterlockedIncrement(&This->refs); } -static ULONG WINAPI ClientIdentity_Release(IInternalUnknown * iface) +static ULONG WINAPI ClientIdentity_Release(IMultiQI * iface) { struct proxy_manager * This = (struct proxy_manager *)iface; ULONG refs = InterlockedDecrement(&This->refs); @@ -221,54 +204,139 @@ static ULONG WINAPI ClientIdentity_Release(IInternalUnknown * iface) return refs; } -static HRESULT WINAPI ClientIdentity_QueryInternalInterface(IInternalUnknown * iface, REFIID riid, void ** ppv) +static HRESULT WINAPI ClientIdentity_QueryMultipleInterfaces(IMultiQI *iface, ULONG cMQIs, MULTI_QI *pMQIs) { - FIXME("(%s, %p): stub!\n", debugstr_guid(riid), ppv); - return E_NOINTERFACE; + struct proxy_manager * This = (struct proxy_manager *)iface; + REMQIRESULT *qiresults = NULL; + ULONG nonlocal_mqis = 0; + ULONG i; + ULONG successful_mqis = 0; + IID *iids = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*iids)); + /* mapping of RemQueryInterface index to QueryMultipleInterfaces index */ + ULONG *mapping = HeapAlloc(GetProcessHeap(), 0, cMQIs * sizeof(*mapping)); + + TRACE("cMQIs: %ld\n", cMQIs); + + /* try to get a local interface - this includes already active proxy + * interfaces and also interfaces exposed by the proxy manager */ + for (i = 0; i < cMQIs; i++) + { + TRACE("iid[%ld] = %s\n", i, debugstr_guid(pMQIs[i].pIID)); + pMQIs[i].hr = proxy_manager_query_local_interface(This, pMQIs[i].pIID, (void **)&pMQIs[i].pItf); + if (pMQIs[i].hr == S_OK) + successful_mqis++; + else + { + iids[nonlocal_mqis] = *pMQIs[i].pIID; + mapping[nonlocal_mqis] = i; + nonlocal_mqis++; + } + } + + TRACE("%ld interfaces not found locally\n", nonlocal_mqis); + + /* if we have more than one interface not found locally then we must try + * to query the remote object for it */ + if (nonlocal_mqis != 0) + { + IRemUnknown *remunk; + HRESULT hr; + IPID *ipid; + + /* 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)->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, + nonlocal_mqis, iids, &qiresults); + if (FAILED(hr)) + ERR("IRemUnknown_RemQueryInterface failed with error 0x%08lx\n", hr); + } + + /* IRemUnknown_RemQueryInterface can return S_FALSE if only some of + * the interfaces were returned */ + if (SUCCEEDED(hr)) + { + /* try to unmarshal each object returned to us */ + for (i = 0; i < nonlocal_mqis; i++) + { + ULONG index = mapping[i]; + HRESULT hrobj = qiresults[i].hResult; + if (hrobj == S_OK) + hrobj = unmarshal_object(&qiresults[i].std, This->parent, + pMQIs[index].pIID, + (void **)&pMQIs[index].pItf); + + if (hrobj == S_OK) + successful_mqis++; + else + ERR("Failed to get pointer to interface %s\n", debugstr_guid(pMQIs[index].pIID)); + pMQIs[index].hr = hrobj; + } + } + + /* free the memory allocated by the proxy */ + CoTaskMemFree(qiresults); + } + + TRACE("%ld/%ld successfully queried\n", successful_mqis, cMQIs); + + HeapFree(GetProcessHeap(), 0, iids); + HeapFree(GetProcessHeap(), 0, mapping); + + if (successful_mqis == cMQIs) + return S_OK; /* we got all requested interfaces */ + else if (successful_mqis == 0) + return E_NOINTERFACE; /* we didn't get any interfaces */ + else + return S_FALSE; /* we got some interfaces */ } -static const IInternalUnknownVtbl ClientIdentity_Vtbl = +static const IMultiQIVtbl ClientIdentity_Vtbl = { ClientIdentity_QueryInterface, ClientIdentity_AddRef, ClientIdentity_Release, - ClientIdentity_QueryInternalInterface + ClientIdentity_QueryMultipleInterfaces }; static HRESULT ifproxy_get_public_ref(struct ifproxy * This) { + HRESULT hr = S_OK; /* FIXME: as this call could possibly be going over the network, we * are going to spend a long time in this CS. We might want to replace * this with a mutex */ EnterCriticalSection(&This->parent->cs); if (This->refs == 0) { - APARTMENT * apt; + IRemUnknown *remunk = NULL; TRACE("getting public ref for ifproxy %p\n", This); - /* FIXME: call IRemUnknown::RemAddRef if necessary */ - - /* FIXME: this is a hack around not yet implemented IRemUnknown */ - if ((apt = COM_ApartmentFromOXID(This->parent->oxid, TRUE))) + hr = proxy_manager_get_remunknown(This->parent, &remunk); + if (hr == S_OK) { - struct stub_manager * stubmgr; - if ((stubmgr = get_stub_manager(apt, This->parent->oid))) - { - stub_manager_ext_addref(stubmgr, 1); - This->refs += 1; - - stub_manager_int_release(stubmgr); - } - - COM_ApartmentRelease(apt); + HRESULT hrref; + REMINTERFACEREF rif; + rif.ipid = This->ipid; + rif.cPublicRefs = NORMALEXTREFS; + rif.cPrivateRefs = 0; + hr = IRemUnknown_RemAddRef(remunk, 1, &rif, &hrref); + if (hr == S_OK && hrref == S_OK) + This->refs += NORMALEXTREFS; + else + ERR("IRemUnknown_RemAddRef returned with 0x%08lx, hrref = 0x%08lx\n", hr, hrref); } - else - FIXME("Need to implement IRemUnknown for inter-process table marshaling\n"); } LeaveCriticalSection(&This->parent->cs); - return S_OK; + return hr; } static HRESULT ifproxy_release_public_refs(struct ifproxy * This) @@ -371,6 +439,33 @@ static HRESULT proxy_manager_construct( return S_OK; } +static HRESULT proxy_manager_query_local_interface(struct proxy_manager * This, REFIID riid, void ** ppv) +{ + HRESULT hr; + struct ifproxy * ifproxy; + + TRACE("%s\n", debugstr_guid(riid)); + + if (IsEqualIID(riid, &IID_IUnknown) || + IsEqualIID(riid, &IID_IMultiQI)) + { + *ppv = (void *)&This->lpVtbl; + IMultiQI_AddRef((IMultiQI *)&This->lpVtbl); + return S_OK; + } + + hr = proxy_manager_find_ifproxy(This, riid, &ifproxy); + if (hr == S_OK) + { + *ppv = ifproxy->iface; + IUnknown_AddRef((IUnknown *)*ppv); + return S_OK; + } + + *ppv = NULL; + return E_NOINTERFACE; +} + static HRESULT proxy_manager_create_ifproxy( struct proxy_manager * This, IPID ipid, REFIID riid, ULONG cPublicRefs, struct ifproxy ** iif_out) @@ -582,7 +677,7 @@ static BOOL find_proxy_manager(APARTMENT * apt, OXID oxid, OID oid, struct proxy if ((oxid == proxy->oxid) && (oid == proxy->oid)) { *proxy_found = proxy; - ClientIdentity_AddRef((IInternalUnknown *)&proxy->lpVtbl); + ClientIdentity_AddRef((IMultiQI *)&proxy->lpVtbl); found = TRUE; break; } @@ -754,7 +849,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI * IUnknown of the proxy manager. */ if (IsEqualIID(riid, &IID_IUnknown)) { - ClientIdentity_AddRef((IInternalUnknown*)&proxy_manager->lpVtbl); + ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl); *object = (LPVOID)(&proxy_manager->lpVtbl); } else @@ -769,7 +864,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI if (hr == S_OK) { /* FIXME: push this AddRef inside proxy_manager_find_ifproxy/create_ifproxy? */ - ClientIdentity_AddRef((IInternalUnknown*)&proxy_manager->lpVtbl); + ClientIdentity_AddRef((IMultiQI*)&proxy_manager->lpVtbl); *object = ifproxy->iface; } } @@ -777,7 +872,7 @@ static HRESULT unmarshal_object(const STDOBJREF *stdobjref, APARTMENT *apt, REFI /* release our reference to the proxy manager - the client/apartment * will hold on to the remaining reference for us */ - if (proxy_manager) ClientIdentity_Release((IInternalUnknown*)&proxy_manager->lpVtbl); + if (proxy_manager) ClientIdentity_Release((IMultiQI*)&proxy_manager->lpVtbl); return hr; } diff --git a/dlls/ole32/oleproxy.c b/dlls/ole32/oleproxy.c index 6c8ecf97198..60747d120b7 100644 --- a/dlls/ole32/oleproxy.c +++ b/dlls/ole32/oleproxy.c @@ -319,7 +319,7 @@ static void WINAPI IRpcProxyBufferImpl_Disconnect(LPRPCPROXYBUFFER iface) { static HRESULT WINAPI CFProxy_QueryInterface(LPCLASSFACTORY iface,REFIID riid, LPVOID *ppv) { - ICOM_THIS_MULTI(CFProxy,lpvtbl_proxy,iface); + ICOM_THIS_MULTI(CFProxy,lpvtbl_cf,iface); if (This->outer_unknown) return IUnknown_QueryInterface(This->outer_unknown, riid, ppv); *ppv = NULL; if (IsEqualIID(&IID_IClassFactory,riid) || IsEqualIID(&IID_IUnknown,riid)) { diff --git a/dlls/ole32/rpc.c b/dlls/ole32/rpc.c index f440c6e5201..9149fb6e66e 100644 --- a/dlls/ole32/rpc.c +++ b/dlls/ole32/rpc.c @@ -129,6 +129,11 @@ read_pipe(HANDLE hf, LPVOID ptr, DWORD size) { return E_FAIL; } if (res!=size) { + if (!res) + { + WARN("%p disconnected\n", hf); + return RPC_E_DISCONNECTED; + } FIXME("Read only %ld of %ld bytes from %p.\n",res,size,hf); return E_FAIL; } @@ -310,10 +315,8 @@ COM_InvokeAndRpcSend(struct rpc *req) { DWORD reqtype; if (!(stub = ipid_to_stubbuffer(&(req->reqh.ipid)))) - { - ERR("Stub not found?\n"); - return E_FAIL; - } + /* ipid_to_stubbuffer will already have logged the error */ + return RPC_E_DISCONNECTED; IUnknown_AddRef(stub); msg.Buffer = req->Buffer; @@ -417,8 +420,9 @@ PipeBuf_SendReceive(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg,ULONG *status) static HRESULT WINAPI PipeBuf_FreeBuffer(LPRPCCHANNELBUFFER iface,RPCOLEMESSAGE* msg) { - FIXME("(%p), stub!\n",msg); - return E_FAIL; + TRACE("(%p)\n",msg); + HeapFree(GetProcessHeap(), 0, msg->Buffer); + return S_OK; } static HRESULT WINAPI diff --git a/dlls/ole32/stubmanager.c b/dlls/ole32/stubmanager.c index c9e754bee75..bdd8c085b61 100644 --- a/dlls/ole32/stubmanager.c +++ b/dlls/ole32/stubmanager.c @@ -539,6 +539,7 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, { HRESULT hr; USHORT i; + USHORT successful_qis = 0; APARTMENT *apt; struct stub_manager *stubmgr; @@ -551,15 +552,22 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, for (i = 0; i < cIids; i++) { - (*ppQIResults)[i].hResult = register_ifstub(apt, &(*ppQIResults)[i].std, - &iids[i], stubmgr->object, - MSHLFLAGS_NORMAL); + HRESULT hrobj = register_ifstub(apt, &(*ppQIResults)[i].std, &iids[i], + stubmgr->object, MSHLFLAGS_NORMAL); + if (hrobj == S_OK) + successful_qis++; + (*ppQIResults)[i].hResult = hrobj; } stub_manager_int_release(stubmgr); COM_ApartmentRelease(apt); - return hr; + if (successful_qis == cIids) + return S_OK; /* we got all requested interfaces */ + else if (successful_qis == 0) + return E_NOINTERFACE; /* we didn't get any interfaces */ + else + return S_FALSE; /* we got some interfaces */ } static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, diff --git a/dlls/ole32/tests/marshal.c b/dlls/ole32/tests/marshal.c index 4063a55591c..229fc8e264a 100644 --- a/dlls/ole32/tests/marshal.c +++ b/dlls/ole32/tests/marshal.c @@ -876,7 +876,7 @@ static void test_proxy_interfaces() if (hr == S_OK) IUnknown_Release(pOtherUnknown); hr = IUnknown_QueryInterface(pProxy, &IID_IMultiQI, (LPVOID*)&pOtherUnknown); - todo_wine { ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI); } + ok_ole_success(hr, IUnknown_QueryInterface IID_IMultiQI); if (hr == S_OK) IUnknown_Release(pOtherUnknown); hr = IUnknown_QueryInterface(pProxy, &IID_IMarshal, (LPVOID*)&pOtherUnknown);