- 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.
diff --git a/dlls/ole32/compobj_private.h b/dlls/ole32/compobj_private.h
index 6b7686b..69af30a 100644
--- a/dlls/ole32/compobj_private.h
+++ b/dlls/ole32/compobj_private.h
@@ -100,7 +100,7 @@
/* 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 ca05070..f711590 100644
--- a/dlls/ole32/marshal.c
+++ b/dlls/ole32/marshal.c
@@ -171,47 +171,30 @@
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 @@
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 @@
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 @@
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 @@
* 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 @@
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 @@
/* 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 6c8ecf9..60747d1 100644
--- a/dlls/ole32/oleproxy.c
+++ b/dlls/ole32/oleproxy.c
@@ -319,7 +319,7 @@
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 f440c6e..9149fb6 100644
--- a/dlls/ole32/rpc.c
+++ b/dlls/ole32/rpc.c
@@ -129,6 +129,11 @@
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 @@
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 @@
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 c9e754b..bdd8c08 100644
--- a/dlls/ole32/stubmanager.c
+++ b/dlls/ole32/stubmanager.c
@@ -539,6 +539,7 @@
{
HRESULT hr;
USHORT i;
+ USHORT successful_qis = 0;
APARTMENT *apt;
struct stub_manager *stubmgr;
@@ -551,15 +552,22 @@
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 4063a555..229fc8e 100644
--- a/dlls/ole32/tests/marshal.c
+++ b/dlls/ole32/tests/marshal.c
@@ -876,7 +876,7 @@
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);