From: Piotr Caban <piotr@codeweavers.com> --- dlls/combase/combase.c | 93 +++++++++++++++++++++++++++++++++- dlls/combase/combase_private.h | 7 +++ dlls/combase/marshal.c | 10 +--- dlls/combase/stubmanager.c | 64 +++++++++++++++++++++-- 4 files changed, 160 insertions(+), 14 deletions(-) diff --git a/dlls/combase/combase.c b/dlls/combase/combase.c index ad4d0bfce68..157528a90cf 100644 --- a/dlls/combase/combase.c +++ b/dlls/combase/combase.c @@ -21,14 +21,17 @@ #include "ntstatus.h" #define USE_COM_CONTEXT_DEF #include "objbase.h" +#include "comsvcs.h" #include "ctxtcall.h" #include "oleauto.h" #include "dde.h" #include "winternl.h" +#include "dcom.h" #include "combase_private.h" #include "wine/debug.h" +#include "wine/exception.h" WINE_DEFAULT_DEBUG_CHANNEL(ole); @@ -2420,6 +2423,7 @@ static struct thread_context IObjContext IObjContext_iface; LONG ref; LONG reported_ref; + OXID oxid; } *mta_context; static inline struct thread_context *impl_from_IComThreadingInfo(IComThreadingInfo *iface) @@ -2590,9 +2594,93 @@ static ULONG WINAPI thread_context_callback_Release(IContextCallback *iface) static HRESULT WINAPI thread_context_callback_ContextCallback(IContextCallback *iface, PFNCONTEXTCALL callback, ComCallData *param, REFIID riid, int method, IUnknown *punk) { - FIXME("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk); + struct thread_context *context = impl_from_IContextCallback(iface); + IObjContext *current_context; + XAptCallback apt_callback; + struct apartment *apt; + STDOBJREF stdobjref; + OXID_INFO oxid_info; + IRundown *rundown; + HRESULT hr; - return E_NOTIMPL; + TRACE("%p, %p, %p, %s, %d, %p\n", iface, callback, param, debugstr_guid(riid), method, punk); + + if (!callback) + return E_INVALIDARG; + + hr = CoGetContextToken((ULONG_PTR *)¤t_context); + if (FAILED(hr)) + return hr; + + if (!(apt = apartment_get_current_or_mta())) + { + ERR("apartment not initialised\n"); + return CO_E_NOTINITIALIZED; + } + rpc_start_remoting(apt); + + if (&context->IObjContext_iface == current_context) + { + IComThreadingInfo *cti = NULL; + GUID thread_id; + + apartment_release(apt); + + if (IsEqualIID(riid, &IID_IEnterActivityWithNoLock)) + { + cti = &context->IComThreadingInfo_iface; + if (FAILED((hr = IComThreadingInfo_GetCurrentLogicalThreadId(cti, &thread_id)))) + return hr; + if (FAILED((hr = IComThreadingInfo_SetCurrentLogicalThreadId(cti, riid)))) + return hr; + } + + __TRY + { + hr = callback(param); + } + __EXCEPT_ALL + { + hr = RPC_E_SERVERFAULT; + } + __ENDTRY + + if (cti) + IComThreadingInfo_SetCurrentLogicalThreadId(cti, &thread_id); + + TRACE("callback returned %lx\n", hr); + return hr; + } + + hr = rpc_resolve_oxid(context->oxid, &oxid_info); + if (SUCCEEDED(hr)) + { + stdobjref.flags = SORFP_NOLIFETIMEMGMT | SORF_NOPING; + stdobjref.cPublicRefs = 1; + stdobjref.oxid = context->oxid; + stdobjref.oid = -1; + stdobjref.ipid = oxid_info.ipidRemUnknown; + hr = unmarshal_object(&stdobjref, apt, MSHCTX_INPROC, NULL, &IID_IRundown, &oxid_info, (void**)&rundown); + apartment_release(apt); + } + if (FAILED(hr)) + return hr; + + apt_callback.pfnCallback = (ULONG_PTR)callback; + apt_callback.pParam = (ULONG_PTR)param; + apt_callback.pServerCtx = (ULONG_PTR)&context->IObjContext_iface; + apt_callback.pUnk = (ULONG_PTR)punk; + apt_callback.iid = *riid; + apt_callback.iMethod = method; + get_process_secret(&apt_callback.guidProcessSecret); + if (IsEqualIID(riid, &IID_ICallbackWithNoReentrancyToApplicationSTA)) + hr = IRundown_DoNonreentrantCallback(rundown, &apt_callback); + else + hr = IRundown_DoCallback(rundown, &apt_callback); + IRundown_Release(rundown); + + TRACE("callback returned %lx\n", hr); + return hr; } static const IContextCallbackVtbl thread_context_callback_vtbl = @@ -2763,6 +2851,7 @@ HRESULT WINAPI CoGetContextToken(ULONG_PTR *token) context->IObjContext_iface.lpVtbl = &thread_object_context_vtbl; context->ref = 1; context->reported_ref = 0; + context->oxid = apt->oxid; if (apt->multi_threaded) { diff --git a/dlls/combase/combase_private.h b/dlls/combase/combase_private.h index ca79356e8eb..76393650f3a 100644 --- a/dlls/combase/combase_private.h +++ b/dlls/combase/combase_private.h @@ -174,8 +174,14 @@ void apartment_revoke_all_classes(const struct apartment *apt); struct apartment * apartment_findfromoxid(OXID oxid); struct apartment * apartment_findfromtid(DWORD tid); +/* private flag indicating that the caller does not want to notify the stub + * when the proxy disconnects or is destroyed */ +#define SORFP_NOLIFETIMEMGMT SORF_OXRES2 + HRESULT marshal_object(struct apartment *apt, STDOBJREF *stdobjref, REFIID riid, IUnknown *object, DWORD dest_context, void *dest_context_data, MSHLFLAGS mshlflags); +HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context, + void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object); /* Stub Manager */ @@ -261,3 +267,4 @@ HRESULT ipid_get_dispatch_params(const IPID *ipid, struct apartment **stub_apt, IID *iid, IUnknown **iface); HRESULT ipid_get_dest_context(const IPID *ipid, MSHCTX *dest_context, void **dest_context_data); HRESULT start_apartment_remote_unknown(struct apartment *apt); +void get_process_secret(GUID *process_secret); diff --git a/dlls/combase/marshal.c b/dlls/combase/marshal.c index 96cb3e25e7e..6e3d35ce580 100644 --- a/dlls/combase/marshal.c +++ b/dlls/combase/marshal.c @@ -36,19 +36,11 @@ HRESULT WINAPI RPC_CreateClientChannel(const OXID *oxid, const IPID *ipid, DWORD dest_context, void *dest_context_data, IRpcChannelBuffer **chan, struct apartment *apt); -static HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, - MSHCTX dest_context, void *dest_context_data, - REFIID riid, const OXID_INFO *oxid_info, - void **object); - /* number of refs given out for normal marshaling */ #define NORMALEXTREFS 5 /* private flag indicating that the object was marshaled as table-weak */ #define SORFP_TABLEWEAK SORF_OXRES1 -/* private flag indicating that the caller does not want to notify the stub - * when the proxy disconnects or is destroyed */ -#define SORFP_NOLIFETIMEMGMT SORF_OXRES2 /* imported interface proxy */ struct ifproxy @@ -2095,7 +2087,7 @@ static HRESULT WINAPI StdMarshalImpl_MarshalInterface(IMarshal *iface, IStream * /* 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, MSHCTX dest_context, +HRESULT unmarshal_object(const STDOBJREF *stdobjref, struct apartment *apt, MSHCTX dest_context, void *dest_context_data, REFIID riid, const OXID_INFO *oxid_info, void **object) { struct proxy_manager *proxy_manager = NULL; diff --git a/dlls/combase/stubmanager.c b/dlls/combase/stubmanager.c index e4ccb8eba00..4756e334f9f 100644 --- a/dlls/combase/stubmanager.c +++ b/dlls/combase/stubmanager.c @@ -32,7 +32,9 @@ #include "windef.h" #include "winbase.h" #include "winuser.h" +#define USE_COM_CONTEXT_DEF #include "objbase.h" +#include "comsvcs.h" #include "rpc.h" #include "wine/debug.h" @@ -831,16 +833,72 @@ static HRESULT WINAPI Rundown_RemChangeRef(IRundown *iface, DWORD flags, return E_NOTIMPL; } +static BOOL WINAPI init_process_secret(PINIT_ONCE init_once, void *param, void **ctx) +{ + GUID *secret = param; + return SUCCEEDED(UuidCreate(secret)); +} + +void get_process_secret(GUID *process_secret) +{ + static INIT_ONCE init_once = INIT_ONCE_STATIC_INIT; + static GUID secret; + + InitOnceExecuteOnce(&init_once, init_process_secret, &secret, NULL); + *process_secret = secret; +} + static HRESULT WINAPI Rundown_DoCallback(IRundown *iface, XAptCallback *pCallbackData) { - FIXME("%p, %p\n", iface, pCallbackData); - return E_NOTIMPL; + HRESULT (WINAPI *callback)(void *) = (void*)(ULONG_PTR)pCallbackData->pfnCallback; + void *param = (void *)(ULONG_PTR)pCallbackData->pParam; + IComThreadingInfo *cti = NULL; + GUID thread_id, secret; + IObjContext *context; + HRESULT hr; + + TRACE("%p, %p\n", iface, pCallbackData); + + get_process_secret(&secret); + if (!IsEqualIID(&secret, &pCallbackData->guidProcessSecret)) + return E_FAIL; + if (FAILED((hr = CoGetContextToken((ULONG_PTR *)&context)))) + return hr; + if (pCallbackData->pServerCtx != (ULONG_PTR)context) + { + ERR("context token doesn't match\n"); + return E_FAIL; + } + + if (IsEqualIID(&IID_IEnterActivityWithNoLock, &pCallbackData->iid)) + { + hr = IObjContext_QueryInterface(context, &IID_IComThreadingInfo, (void **)&cti); + if (FAILED(hr)) + return hr; + hr = IComThreadingInfo_GetCurrentLogicalThreadId(cti, &thread_id); + if (SUCCEEDED(hr)) + hr = IComThreadingInfo_SetCurrentLogicalThreadId(cti, &IID_IEnterActivityWithNoLock); + if (FAILED(hr)) + { + IComThreadingInfo_Release(cti); + return hr; + } + } + + hr = callback(param); + + if (cti) + { + IComThreadingInfo_SetCurrentLogicalThreadId(cti, &thread_id); + IComThreadingInfo_Release(cti); + } + return hr; } static HRESULT WINAPI Rundown_DoNonreentrantCallback(IRundown *iface, XAptCallback *pCallbackData) { FIXME("%p, %p\n", iface, pCallbackData); - return E_NOTIMPL; + return IRundown_DoCallback(iface, pCallbackData); } static HRESULT WINAPI Rundown_GetInterfaceNameFromIPID(IRundown *iface, -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10995