From: Nikolay Sivov nsivov@codeweavers.com
Signed-off-by: Nikolay Sivov nsivov@codeweavers.com Signed-off-by: Huw Davies huw@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)