[PATCH v2 3/5] combase: Move CoUnmarshalInterface().

Huw Davies huw at codeweavers.com
Tue Sep 1 09:16:31 CDT 2020


From: Nikolay Sivov <nsivov at codeweavers.com>

Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
Signed-off-by: Huw Davies <huw at codeweavers.com>
---
 dlls/combase/apartment.c       |   5 ++
 dlls/combase/combase.spec      |   2 +-
 dlls/combase/combase_private.h |   3 +
 dlls/combase/marshal.c         | 146 +++++++++++++++++++++++++++++++++
 dlls/ole32/marshal.c           | 143 +-------------------------------
 dlls/ole32/ole32.spec          |   3 +-
 6 files changed, 159 insertions(+), 143 deletions(-)

diff --git a/dlls/combase/apartment.c b/dlls/combase/apartment.c
index 1637d674222..6aa053bdd52 100644
--- a/dlls/combase/apartment.c
+++ b/dlls/combase/apartment.c
@@ -1270,6 +1270,11 @@ HWND WINAPI apartment_getwindow(const struct apartment *apt)
     return apt->win;
 }
 
+OXID apartment_getoxid(const struct apartment *apt)
+{
+    return apt->oxid;
+}
+
 void apartment_global_cleanup(void)
 {
     if (apt_win_class)
diff --git a/dlls/combase/combase.spec b/dlls/combase/combase.spec
index e1ffdc82539..7b165b131ce 100644
--- a/dlls/combase/combase.spec
+++ b/dlls/combase/combase.spec
@@ -166,7 +166,7 @@
 @ stdcall CoUninitialize()
 @ stub CoUnloadingWOW
 @ stdcall CoUnmarshalHresult(ptr ptr)
-@ stdcall CoUnmarshalInterface(ptr ptr ptr) ole32.CoUnmarshalInterface
+@ stdcall CoUnmarshalInterface(ptr ptr ptr)
 @ stub CoVrfCheckThreadState
 @ stub CoVrfGetThreadState
 @ stub CoVrfReleaseThreadState
diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h
index cc1c3d34388..210844805bb 100644
--- a/dlls/combase/combase_private.h
+++ b/dlls/combase/combase_private.h
@@ -106,6 +106,7 @@ HWND WINAPI apartment_getwindow(const struct apartment *apt) DECLSPEC_HIDDEN;
 HRESULT WINAPI apartment_createwindowifneeded(struct apartment *apt) DECLSPEC_HIDDEN;
 void apartment_freeunusedlibraries(struct apartment *apt, DWORD unload_delay) DECLSPEC_HIDDEN;
 void apartment_global_cleanup(void) DECLSPEC_HIDDEN;
+OXID apartment_getoxid(const struct apartment *apt) DECLSPEC_HIDDEN;
 
 /* RpcSs interface */
 HRESULT rpcss_get_next_seqid(DWORD *id) DECLSPEC_HIDDEN;
@@ -224,3 +225,5 @@ ULONG WINAPI stub_manager_ext_addref(struct stub_manager *m, ULONG refs, BOOL ta
 ULONG WINAPI stub_manager_ext_release(struct stub_manager *m, ULONG refs, BOOL tableweak, BOOL last_unlock_releases) DECLSPEC_HIDDEN;
 struct stub_manager * WINAPI get_stub_manager(struct apartment *apt, OID oid);
 void WINAPI stub_manager_release_marshal_data(struct stub_manager *m, ULONG refs, const IPID *ipid, BOOL tableweak);
+BOOL WINAPI stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid);
+BOOL WINAPI stub_manager_notify_unmarshal(struct stub_manager *m, const IPID *ipid);
diff --git a/dlls/combase/marshal.c b/dlls/combase/marshal.c
index bfe31ff17dd..37ec0ca2207 100644
--- a/dlls/combase/marshal.c
+++ b/dlls/combase/marshal.c
@@ -29,6 +29,11 @@
 
 WINE_DEFAULT_DEBUG_CHANNEL(ole);
 
+HRESULT WINAPI unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
+                                MSHCTX dest_context, void *dest_context_data,
+                                REFIID riid, const OXID_INFO *oxid_info,
+                                void **object);
+
 /* private flag indicating that the object was marshaled as table-weak */
 #define SORFP_TABLEWEAK SORF_OXRES1
 
@@ -648,3 +653,144 @@ HRESULT WINAPI CoReleaseMarshalData(IStream *stream)
     IMarshal_Release(marshal);
     return hr;
 }
+
+static HRESULT std_unmarshal_interface(MSHCTX dest_context, void *dest_context_data,
+        IStream *stream, REFIID riid, void **ppv)
+{
+    struct stub_manager *stubmgr = NULL;
+    struct OR_STANDARD obj;
+    ULONG res;
+    HRESULT hres;
+    struct apartment *apt, *stub_apt;
+
+    TRACE("(...,%s,....)\n", debugstr_guid(riid));
+
+    /* we need an apartment to unmarshal into */
+    if (!(apt = apartment_get_current_or_mta()))
+    {
+        ERR("Apartment not initialized\n");
+        return CO_E_NOTINITIALIZED;
+    }
+
+    /* read STDOBJREF from wire */
+    hres = IStream_Read(stream, &obj, FIELD_OFFSET(struct OR_STANDARD, saResAddr.aStringArray), &res);
+    if (hres != S_OK)
+    {
+        apartment_release(apt);
+        return STG_E_READFAULT;
+    }
+
+    if (obj.saResAddr.wNumEntries)
+    {
+        ERR("unsupported size of DUALSTRINGARRAY\n");
+        return E_NOTIMPL;
+    }
+
+    /* check if we're marshalling back to ourselves */
+    if ((apartment_getoxid(apt) == obj.std.oxid) && (stubmgr = get_stub_manager(apt, obj.std.oid)))
+    {
+        TRACE("Unmarshalling object marshalled in same apartment for iid %s, "
+              "returning original object %p\n", debugstr_guid(riid), stubmgr->object);
+
+        hres = IUnknown_QueryInterface(stubmgr->object, riid, ppv);
+
+        /* unref the ifstub. FIXME: only do this on success? */
+        if (!stub_manager_is_table_marshaled(stubmgr, &obj.std.ipid))
+            stub_manager_ext_release(stubmgr, obj.std.cPublicRefs, obj.std.flags & SORFP_TABLEWEAK, FALSE);
+
+        stub_manager_int_release(stubmgr);
+        apartment_release(apt);
+        return hres;
+    }
+
+    /* notify stub manager about unmarshal if process-local object.
+     * note: if the oxid is not found then we and native will quite happily
+     * ignore table marshaling and normal marshaling rules regarding number of
+     * unmarshals, etc, but if you abuse these rules then your proxy could end
+     * up returning RPC_E_DISCONNECTED. */
+    if ((stub_apt = apartment_findfromoxid(obj.std.oxid)))
+    {
+        if ((stubmgr = get_stub_manager(stub_apt, obj.std.oid)))
+        {
+            if (!stub_manager_notify_unmarshal(stubmgr, &obj.std.ipid))
+                hres = CO_E_OBJNOTCONNECTED;
+        }
+        else
+        {
+            WARN("Couldn't find object for OXID %s, OID %s, assuming disconnected\n",
+                wine_dbgstr_longlong(obj.std.oxid),
+                wine_dbgstr_longlong(obj.std.oid));
+            hres = CO_E_OBJNOTCONNECTED;
+        }
+    }
+    else
+        TRACE("Treating unmarshal from OXID %s as inter-process\n",
+            wine_dbgstr_longlong(obj.std.oxid));
+
+    if (hres == S_OK)
+        hres = unmarshal_object(&obj.std, apt, dest_context,
+                                dest_context_data, riid,
+                                stubmgr ? &stubmgr->oxid_info : NULL, ppv);
+
+    if (stubmgr) stub_manager_int_release(stubmgr);
+    if (stub_apt) apartment_release(stub_apt);
+
+    if (hres != S_OK) WARN("Failed with error 0x%08x\n", hres);
+    else TRACE("Successfully created proxy %p\n", *ppv);
+
+    apartment_release(apt);
+    return hres;
+}
+
+/***********************************************************************
+ *            CoUnmarshalInterface        (combase.@)
+ */
+HRESULT WINAPI CoUnmarshalInterface(IStream *stream, REFIID riid, void **ppv)
+{
+    IMarshal *marshal;
+    IUnknown *object;
+    HRESULT hr;
+    IID iid;
+
+    TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv);
+
+    if (!stream || !ppv)
+        return E_INVALIDARG;
+
+    hr = get_unmarshaler_from_stream(stream, &marshal, &iid);
+    if (hr == S_FALSE)
+    {
+        hr = std_unmarshal_interface(0, NULL, stream, &iid, (void **)&object);
+        if (hr != S_OK)
+            ERR("StdMarshal UnmarshalInterface failed, hr %#x\n", hr);
+    }
+    else if (hr == S_OK)
+    {
+        /* call the helper object to do the actual unmarshaling */
+        hr = IMarshal_UnmarshalInterface(marshal, stream, &iid, (void **)&object);
+        IMarshal_Release(marshal);
+        if (hr != S_OK)
+            ERR("IMarshal::UnmarshalInterface failed, hr %#x\n", hr);
+    }
+
+    if (hr == S_OK)
+    {
+        /* IID_NULL means use the interface ID of the marshaled object */
+        if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
+        {
+            TRACE("requested interface != marshalled interface, additional QI needed\n");
+            hr = IUnknown_QueryInterface(object, riid, ppv);
+            if (hr != S_OK)
+                ERR("Couldn't query for interface %s, hr %#x\n", debugstr_guid(riid), hr);
+            IUnknown_Release(object);
+        }
+        else
+        {
+            *ppv = object;
+        }
+    }
+
+    TRACE("completed with hr 0x%x\n", hr);
+
+    return hr;
+}
diff --git a/dlls/ole32/marshal.c b/dlls/ole32/marshal.c
index e462c9ffd48..f8b4aecc544 100644
--- a/dlls/ole32/marshal.c
+++ b/dlls/ole32/marshal.c
@@ -95,7 +95,7 @@ static inline struct proxy_manager *impl_from_IClientSecurity( IClientSecurity *
     return CONTAINING_RECORD(iface, struct proxy_manager, IClientSecurity_iface);
 }
 
-static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
+HRESULT WINAPI unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
                                 MSHCTX dest_context, void *dest_context_data,
                                 REFIID riid, const OXID_INFO *oxid_info,
                                 void **object);
@@ -1347,7 +1347,7 @@ StdMarshalImpl_MarshalInterface(
 /* helper for StdMarshalImpl_UnmarshalInterface - does the unmarshaling with
  * no questions asked about the rules surrounding same-apartment unmarshals
  * and table marshaling */
-static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
+HRESULT WINAPI unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt,
                                 MSHCTX dest_context, void *dest_context_data,
                                 REFIID riid, const OXID_INFO *oxid_info,
                                 void **object)
@@ -1698,145 +1698,6 @@ HRESULT WINAPI CoGetStandardMarshal(REFIID riid, IUnknown *pUnk,
     return StdMarshalImpl_Construct(&IID_IMarshal, dwDestContext, pvDestContext, (void**)ppMarshal);
 }
 
-/***********************************************************************
- *		get_unmarshaler_from_stream	[internal]
- *
- * Creates an IMarshal* object according to the data marshaled to the stream.
- * The function leaves the stream pointer at the start of the data written
- * to the stream by the IMarshal* object.
- */
-static HRESULT get_unmarshaler_from_stream(IStream *stream, IMarshal **marshal, IID *iid)
-{
-    HRESULT hr;
-    ULONG res;
-    OBJREF objref;
-
-    /* read common OBJREF header */
-    hr = IStream_Read(stream, &objref, FIELD_OFFSET(OBJREF, u_objref), &res);
-    if (hr != S_OK || (res != FIELD_OFFSET(OBJREF, u_objref)))
-    {
-        ERR("Failed to read common OBJREF header, 0x%08x\n", hr);
-        return STG_E_READFAULT;
-    }
-
-    /* sanity check on header */
-    if (objref.signature != OBJREF_SIGNATURE)
-    {
-        ERR("Bad OBJREF signature 0x%08x\n", objref.signature);
-        return RPC_E_INVALID_OBJREF;
-    }
-
-    if (iid) *iid = objref.iid;
-
-    /* FIXME: handler marshaling */
-    if (objref.flags & OBJREF_STANDARD)
-    {
-        TRACE("Using standard unmarshaling\n");
-        *marshal = NULL;
-        return S_FALSE;
-    }
-    else if (objref.flags & OBJREF_CUSTOM)
-    {
-        ULONG custom_header_size = FIELD_OFFSET(OBJREF, u_objref.u_custom.pData) - 
-                                   FIELD_OFFSET(OBJREF, u_objref.u_custom);
-        TRACE("Using custom unmarshaling\n");
-        /* read constant sized OR_CUSTOM data from stream */
-        hr = IStream_Read(stream, &objref.u_objref.u_custom,
-                          custom_header_size, &res);
-        if (hr != S_OK || (res != custom_header_size))
-        {
-            ERR("Failed to read OR_CUSTOM header, 0x%08x\n", hr);
-            return STG_E_READFAULT;
-        }
-        /* now create the marshaler specified in the stream */
-        hr = CoCreateInstance(&objref.u_objref.u_custom.clsid, NULL,
-                              CLSCTX_INPROC_SERVER, &IID_IMarshal,
-                              (LPVOID*)marshal);
-    }
-    else
-    {
-        FIXME("Invalid or unimplemented marshaling type specified: %x\n",
-            objref.flags);
-        return RPC_E_INVALID_OBJREF;
-    }
-
-    if (hr != S_OK)
-        ERR("Failed to create marshal, 0x%08x\n", hr);
-
-    return hr;
-}
-
-/***********************************************************************
- *		CoUnmarshalInterface	[OLE32.@]
- *
- * Unmarshals an object from a stream by creating a proxy to the remote
- * object, if necessary.
- *
- * PARAMS
- *
- *  pStream [I] Stream containing the marshaled object.
- *  riid    [I] Interface identifier of the object to create a proxy to.
- *  ppv     [O] Address where proxy will be stored.
- *
- * RETURNS
- *
- *  Success: S_OK.
- *  Failure: HRESULT code.
- *
- * SEE ALSO
- *  CoMarshalInterface().
- */
-HRESULT WINAPI CoUnmarshalInterface(IStream *pStream, REFIID riid, LPVOID *ppv)
-{
-    HRESULT hr;
-    LPMARSHAL pMarshal;
-    IID iid;
-    IUnknown *object;
-
-    TRACE("(%p, %s, %p)\n", pStream, debugstr_guid(riid), ppv);
-
-    if (!pStream || !ppv)
-        return E_INVALIDARG;
-
-    hr = get_unmarshaler_from_stream(pStream, &pMarshal, &iid);
-    if (hr == S_FALSE)
-    {
-        hr = std_unmarshal_interface(0, NULL, pStream, &iid, (void**)&object);
-        if (hr != S_OK)
-            ERR("StdMarshal UnmarshalInterface failed, 0x%08x\n", hr);
-    }
-    else if (hr == S_OK)
-    {
-        /* call the helper object to do the actual unmarshaling */
-        hr = IMarshal_UnmarshalInterface(pMarshal, pStream, &iid, (LPVOID*)&object);
-        IMarshal_Release(pMarshal);
-        if (hr != S_OK)
-            ERR("IMarshal::UnmarshalInterface failed, 0x%08x\n", hr);
-    }
-
-    if (hr == S_OK)
-    {
-        /* IID_NULL means use the interface ID of the marshaled object */
-        if (!IsEqualIID(riid, &IID_NULL) && !IsEqualIID(riid, &iid))
-        {
-            TRACE("requested interface != marshalled interface, additional QI needed\n");
-            hr = IUnknown_QueryInterface(object, riid, ppv);
-            if (hr != S_OK)
-                ERR("Couldn't query for interface %s, hr = 0x%08x\n",
-                    debugstr_guid(riid), hr);
-            IUnknown_Release(object);
-        }
-        else
-        {
-            *ppv = object;
-        }
-    }
-
-    TRACE("completed with hr 0x%x\n", hr);
-    
-    return hr;
-}
-
 static HRESULT WINAPI StdMarshalCF_QueryInterface(LPCLASSFACTORY iface,
                                                   REFIID riid, LPVOID *ppv)
 {
diff --git a/dlls/ole32/ole32.spec b/dlls/ole32/ole32.spec
index 2ecfcf6b510..ee478c73d2b 100644
--- a/dlls/ole32/ole32.spec
+++ b/dlls/ole32/ole32.spec
@@ -90,7 +90,7 @@
 @ stdcall CoUninitialize() combase.CoUninitialize
 @ stub CoUnloadingWOW
 @ stdcall CoUnmarshalHresult(ptr ptr) combase.CoUnmarshalHresult
-@ stdcall CoUnmarshalInterface(ptr ptr ptr)
+@ stdcall CoUnmarshalInterface(ptr ptr ptr) combase.CoUnmarshalInterface
 @ stdcall CoWaitForMultipleHandles(long long long ptr ptr) combase.CoWaitForMultipleHandles
 @ stdcall CreateAntiMoniker(ptr)
 @ stdcall CreateBindCtx(long ptr)
@@ -302,5 +302,6 @@
 @ stdcall Internal_apartment_disconnectproxies(ptr)
 @ stdcall Internal_RPC_ExecuteCall(ptr)
 @ stdcall marshal_object(ptr ptr ptr ptr long ptr long)
+@ stdcall unmarshal_object(ptr ptr long ptr ptr ptr ptr)
 @ stdcall RPC_CreateServerChannel(long ptr ptr)
 @ stdcall RPC_UnregisterInterface(ptr long)
-- 
2.23.0




More information about the wine-devel mailing list