- Make proxy manager use IMultiQI instead of IInternalUnknown as tests
authorRobert Shearman <rob@codeweavers.com>
Wed, 26 Jan 2005 21:07:05 +0000 (21:07 +0000)
committerAlexandre Julliard <julliard@winehq.org>
Wed, 26 Jan 2005 21:07:05 +0000 (21:07 +0000)
  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
dlls/ole32/marshal.c
dlls/ole32/oleproxy.c
dlls/ole32/rpc.c
dlls/ole32/stubmanager.c
dlls/ole32/tests/marshal.c

index 6b7686bd791e80e06d9b5cec572e76c77b36b976..69af30a7226db61b708bd089b1d0c5f9d367cb36 100644 (file)
@@ -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) */
index ca050700479b55d8bc40027408cb8f2b001316b3..f7115908504a5097d1786bf16b1ea5ce00f11bfc 100644 (file)
@@ -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;
-    }
-
-    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 */
+    mqi.pIID = riid;
+    hr = IMultiQI_QueryMultipleInterfaces(iface, 1, &mqi);
+    *ppv = (void *)mqi.pItf;
 
-    *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;
 }
index 6c8ecf9719873a236b0011c0e8bd0ca8f2485cd3..60747d120b7688a439ee0f6c37ab9f90a993d7de 100644 (file)
@@ -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)) {
index f440c6e520149de47ec61753ecb114bda026360b..9149fb6e66e5b9bf17fb84f23a0f3d75295d5159 100644 (file)
@@ -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
index c9e754bee757f4a5be939a33ce224f7ac26344cc..bdd8c085b610a76c957d52b759c08d2b3045a819 100644 (file)
@@ -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,
index 4063a55591c4cdd4fe6d74cf37601c12e88bfe6c..229fc8e264a7517f960548680d0f42c5580c255b 100644 (file)
@@ -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);