[PATCH 0/4] MR10995: combase: Implement IContextCallback::ContextCallback.
IRundown definition is based on https://www.mdsec.co.uk/2022/04/process-injection-via-component-object-model... -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10995
From: Piotr Caban <piotr@codeweavers.com> --- dlls/combase/dcom.idl | 72 +++++++++++++++++++++++++++++++++++++++++++ dlls/ole32/dcom.idl | 56 +++++++++++++++++++++++++++++++++ 2 files changed, 128 insertions(+) diff --git a/dlls/combase/dcom.idl b/dlls/combase/dcom.idl index 56e3152456c..84b7ab346ec 100644 --- a/dlls/combase/dcom.idl +++ b/dlls/combase/dcom.idl @@ -21,6 +21,7 @@ #pragma makedep header +#include "hstring.idl" #include "wine/orpc.idl" [ @@ -60,3 +61,74 @@ interface IRemUnknown : IUnknown [in] unsigned short cInterfaceRefs, [in, size_is(cInterfaceRefs)] REMINTERFACEREF *InterfaceRefs); } + +[ + object, + uuid(00000142-0000-0000-C000-000000000046) +] +interface IRemUnknown2 : IRemUnknown +{ + typedef [unique] IRemUnknown2 *LPREMUNKNOWN2; + + HRESULT RemQueryInterface2( + [in] REFIPID ripid, + [in] unsigned short cIids, + [in, size_is(cIids)] IID *iids, + [out, size_is(cIids)] HRESULT *phr, + [out, size_is(cIids)] MInterfacePointer **ppMIF); +} + +[ + object, + uuid(0000013C-0000-0000-C000-000000000046) +] +interface IRemUnknownN : IRemUnknown2 +{ + const DWORD IRUF_CONVERTTOWEAK = 0x01; + const DWORD IRUF_CONVERTTOSTRONG = 0x02; + const DWORD IRUF_DISCONNECTIFLASTSTRONG = 0x04; + + typedef struct tagXAptCallback + { + DWORD64 pfnCallback; + DWORD64 pParam; + DWORD64 pServerCtx; + DWORD64 pUnk; + GUID iid; + INT iMethod; + GUID guidProcessSecret; + } XAptCallback; + + HRESULT AcknowledgeMarshalingSets( + [in] WORD cMarshalingSets, + [in, size_is(cMarshalingSets)] DWORD64 *pMarshalingSets); + + HRESULT RemChangeRef( + [in] DWORD flags, + [in] WORD cInterfaceRefs, + [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[]); + + HRESULT DoCallback( + [in] XAptCallback *pCallbackData); + + HRESULT DoNonreentrantCallback( + [in] XAptCallback *pCallbackData); + + HRESULT GetInterfaceNameFromIPID( + [in] REFIPID ripid, + [out] HSTRING *interfaceName); +} + +[ + object, + uuid(00000134-0000-0000-C000-000000000046), +] +interface IRundown : IRemUnknownN +{ + const DWORD MAX_OID_RUNDOWNS_PER_CALL = 100; + + HRESULT RundownOid( + [in, range(1, MAX_OID_RUNDOWNS_PER_CALL)] DWORD cOid, + [in, size_is(cOid)] OID aOid[], + [out, size_is(cOid)] BYTE aRundownStatus[]); +} diff --git a/dlls/ole32/dcom.idl b/dlls/ole32/dcom.idl index 05c0513362f..7004b8e80d0 100644 --- a/dlls/ole32/dcom.idl +++ b/dlls/ole32/dcom.idl @@ -22,6 +22,7 @@ #pragma makedep proxy #pragma makedep register +#include "hstring.idl" #include "wine/orpc.idl" [ @@ -82,6 +83,61 @@ interface IRemUnknown2 : IRemUnknown [out, size_is(cIids)] MInterfacePointer **ppMIF); } +[ + object, + uuid(0000013C-0000-0000-C000-000000000046) +] +interface IRemUnknownN : IRemUnknown2 +{ + const DWORD IRUF_CONVERTTOWEAK = 0x01; + const DWORD IRUF_CONVERTTOSTRONG = 0x02; + const DWORD IRUF_DISCONNECTIFLASTSTRONG = 0x04; + + typedef struct tagXAptCallback + { + DWORD64 pfnCallback; + DWORD64 pParam; + DWORD64 pServerCtx; + DWORD64 pUnk; + GUID iid; + INT iMethod; + GUID guidProcessSecret; + } XAptCallback; + + HRESULT AcknowledgeMarshalingSets( + [in] WORD cMarshalingSets, + [in, size_is(cMarshalingSets)] DWORD64 *pMarshalingSets); + + HRESULT RemChangeRef( + [in] DWORD flags, + [in] WORD cInterfaceRefs, + [in, size_is(cInterfaceRefs)] REMINTERFACEREF InterfaceRefs[]); + + HRESULT DoCallback( + [in] XAptCallback *pCallbackData); + + HRESULT DoNonreentrantCallback( + [in] XAptCallback *pCallbackData); + + HRESULT GetInterfaceNameFromIPID( + [in] REFIPID ripid, + [out] HSTRING *interfaceName); +} + +[ + object, + uuid(00000134-0000-0000-C000-000000000046), +] +interface IRundown : IRemUnknownN +{ + const DWORD MAX_OID_RUNDOWNS_PER_CALL = 100; + + HRESULT RundownOid( + [in, range(1, MAX_OID_RUNDOWNS_PER_CALL)] DWORD cOid, + [in, size_is(cOid)] OID aOid[], + [out, size_is(cOid)] BYTE aRundownStatus[]); +} + [ uuid(99fcfec4-5260-101b-bbcb-00aa0021347a), pointer_default(unique) -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10995
From: Piotr Caban <piotr@codeweavers.com> --- dlls/combase/marshal.c | 2 +- dlls/combase/stubmanager.c | 151 +++++++++++++++++++++++++------------ 2 files changed, 104 insertions(+), 49 deletions(-) diff --git a/dlls/combase/marshal.c b/dlls/combase/marshal.c index f638604f5a3..96cb3e25e7e 100644 --- a/dlls/combase/marshal.c +++ b/dlls/combase/marshal.c @@ -1873,7 +1873,7 @@ static HRESULT proxy_manager_get_remunknown(struct proxy_manager * This, IRemUnk /* do the unmarshal */ hr = unmarshal_object(&stdobjref, apt, This->dest_context, - This->dest_context_data, &IID_IRemUnknown, + This->dest_context_data, &IID_IRundown, &This->oxid_info, (void**)remunk); if (hr == S_OK && called_in_original_apt) { diff --git a/dlls/combase/stubmanager.c b/dlls/combase/stubmanager.c index 566f92c8a75..e4ccb8eba00 100644 --- a/dlls/combase/stubmanager.c +++ b/dlls/combase/stubmanager.c @@ -638,50 +638,36 @@ BOOL stub_manager_is_table_marshaled(struct stub_manager *m, const IPID *ipid) /***************************************************************************** * - * IRemUnknown implementation + * IRundown / IRemUnknown implementation * * * Note: this object is not related to the lifetime of a stub_manager, but it * interacts with stub managers. */ -typedef struct rem_unknown +typedef struct { - IRemUnknown IRemUnknown_iface; + IRundown IRundown_iface; LONG refs; -} RemUnknown; +} Rundown; -static const IRemUnknownVtbl RemUnknown_Vtbl; - -static inline RemUnknown *impl_from_IRemUnknown(IRemUnknown *iface) -{ - return CONTAINING_RECORD(iface, RemUnknown, IRemUnknown_iface); -} - -/* construct an IRemUnknown object with one outstanding reference */ -static HRESULT RemUnknown_Construct(IRemUnknown **ppRemUnknown) +static inline Rundown *impl_from_IRundown(IRundown *iface) { - RemUnknown *object = malloc(sizeof(*object)); - - if (!object) - return E_OUTOFMEMORY; - - object->IRemUnknown_iface.lpVtbl = &RemUnknown_Vtbl; - object->refs = 1; - - *ppRemUnknown = &object->IRemUnknown_iface; - return S_OK; + return CONTAINING_RECORD(iface, Rundown, IRundown_iface); } -static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, void **ppv) +static HRESULT WINAPI Rundown_QueryInterface(IRundown *iface, REFIID riid, void **ppv) { TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), ppv); if (IsEqualIID(riid, &IID_IUnknown) || - IsEqualIID(riid, &IID_IRemUnknown)) + IsEqualIID(riid, &IID_IRemUnknown) || + IsEqualIID(riid, &IID_IRemUnknown2) || + IsEqualIID(riid, &IID_IRemUnknownN) || + IsEqualIID(riid, &IID_IRundown)) { *ppv = iface; - IRemUnknown_AddRef(iface); + IRundown_AddRef(iface); return S_OK; } @@ -692,31 +678,31 @@ static HRESULT WINAPI RemUnknown_QueryInterface(IRemUnknown *iface, REFIID riid, return E_NOINTERFACE; } -static ULONG WINAPI RemUnknown_AddRef(IRemUnknown *iface) +static ULONG WINAPI Rundown_AddRef(IRundown *iface) { ULONG refs; - RemUnknown *remunk = impl_from_IRemUnknown(iface); + Rundown *rundown = impl_from_IRundown(iface); - refs = InterlockedIncrement(&remunk->refs); + refs = InterlockedIncrement(&rundown->refs); TRACE("%p before: %ld\n", iface, refs-1); return refs; } -static ULONG WINAPI RemUnknown_Release(IRemUnknown *iface) +static ULONG WINAPI Rundown_Release(IRundown *iface) { ULONG refs; - RemUnknown *remunk = impl_from_IRemUnknown(iface); + Rundown *rundown = impl_from_IRundown(iface); - refs = InterlockedDecrement(&remunk->refs); + refs = InterlockedDecrement(&rundown->refs); if (!refs) - free(remunk); + free(rundown); TRACE("%p after: %ld\n", iface, refs); return refs; } -static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, +static HRESULT WINAPI Rundown_RemQueryInterface(IRundown *iface, REFIPID ripid, ULONG cRefs, USHORT cIids, IID *iids /* [size_is(cIids)] */, REMQIRESULT **ppQIResults /* [size_is(,cIids)] */) { @@ -758,7 +744,7 @@ static HRESULT WINAPI RemUnknown_RemQueryInterface(IRemUnknown *iface, return S_FALSE; /* we got some interfaces */ } -static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, +static HRESULT WINAPI Rundown_RemAddRef(IRundown *iface, USHORT cInterfaceRefs, REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */, HRESULT *pResults /* [size_is(cInterfaceRefs)] */) @@ -791,7 +777,7 @@ static HRESULT WINAPI RemUnknown_RemAddRef(IRemUnknown *iface, return hr; } -static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, +static HRESULT WINAPI Rundown_RemRelease(IRundown *iface, USHORT cInterfaceRefs, REMINTERFACEREF* InterfaceRefs /* [size_is(cInterfaceRefs)] */) { @@ -824,35 +810,104 @@ static HRESULT WINAPI RemUnknown_RemRelease(IRemUnknown *iface, return hr; } -static const IRemUnknownVtbl RemUnknown_Vtbl = +static HRESULT WINAPI Rundown_RemQueryInterface2(IRundown *iface, REFIPID ripid, + unsigned short cIids, IID *iids, HRESULT *phr, MInterfacePointer **ppMIF) { - RemUnknown_QueryInterface, - RemUnknown_AddRef, - RemUnknown_Release, - RemUnknown_RemQueryInterface, - RemUnknown_RemAddRef, - RemUnknown_RemRelease + FIXME("%p, %p, %hu, %p, %p, %p\n", iface, ripid, cIids, iids, phr, ppMIF); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_AcknowledgeMarshalingSets(IRundown *iface, + WORD cMarshalingSets, DWORD64 *pMarshalingSets) +{ + FIXME("%p, %hu, %p\n", iface, cMarshalingSets, pMarshalingSets); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_RemChangeRef(IRundown *iface, DWORD flags, + WORD cInterfaceRefs, REMINTERFACEREF InterfaceRefs[]) +{ + FIXME("%p, %lu, %hu, %p\n", iface, flags, cInterfaceRefs, InterfaceRefs); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_DoCallback(IRundown *iface, XAptCallback *pCallbackData) +{ + FIXME("%p, %p\n", iface, pCallbackData); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_DoNonreentrantCallback(IRundown *iface, XAptCallback *pCallbackData) +{ + FIXME("%p, %p\n", iface, pCallbackData); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_GetInterfaceNameFromIPID(IRundown *iface, + REFIPID ripid, HSTRING *interfaceName) +{ + FIXME("%p, %p %p\n", iface, ripid, interfaceName); + return E_NOTIMPL; +} + +static HRESULT WINAPI Rundown_RundownOid(IRundown *iface, + DWORD cOid, OID aOid[], BYTE aRundownStatus[]) +{ + FIXME("%p, %lu, %p %p\n", iface, cOid, aOid, aRundownStatus); + return E_NOTIMPL; +} + +static const IRundownVtbl Rundown_Vtbl = +{ + Rundown_QueryInterface, + Rundown_AddRef, + Rundown_Release, + Rundown_RemQueryInterface, + Rundown_RemAddRef, + Rundown_RemRelease, + Rundown_RemQueryInterface2, + Rundown_AcknowledgeMarshalingSets, + Rundown_RemChangeRef, + Rundown_DoCallback, + Rundown_DoNonreentrantCallback, + Rundown_GetInterfaceNameFromIPID, + Rundown_RundownOid }; +/* construct an IRundown object with one outstanding reference */ +static HRESULT Rundown_Construct(IRundown **rundown) +{ + Rundown *object = malloc(sizeof(*object)); + + if (!object) + return E_OUTOFMEMORY; + + object->IRundown_iface.lpVtbl = &Rundown_Vtbl; + object->refs = 1; + + *rundown = &object->IRundown_iface; + return S_OK; +} + /* starts the IRemUnknown listener for the current apartment */ HRESULT start_apartment_remote_unknown(struct apartment *apt) { - IRemUnknown *pRemUnknown; + IRundown *pRundown; HRESULT hr = S_OK; EnterCriticalSection(&apt->cs); if (!apt->remunk_exported) { - /* create the IRemUnknown object */ - hr = RemUnknown_Construct(&pRemUnknown); + /* create the IRundown object */ + hr = Rundown_Construct(&pRundown); if (hr == S_OK) { STDOBJREF stdobjref; /* dummy - not used */ /* register it with the stub manager */ - hr = marshal_object(apt, &stdobjref, &IID_IRemUnknown, (IUnknown *)pRemUnknown, + hr = marshal_object(apt, &stdobjref, &IID_IRundown, (IUnknown *)pRundown, MSHCTX_DIFFERENTMACHINE, NULL, MSHLFLAGS_NORMAL|MSHLFLAGSP_REMUNKNOWN); /* release our reference to the object as the stub manager will manage the life cycle for us */ - IRemUnknown_Release(pRemUnknown); + IRundown_Release(pRundown); if (hr == S_OK) apt->remunk_exported = TRUE; } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10995
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
From: Piotr Caban <piotr@codeweavers.com> --- dlls/ole32/tests/compobj.c | 163 +++++++++++++++++++++++++++++++++++-- 1 file changed, 156 insertions(+), 7 deletions(-) diff --git a/dlls/ole32/tests/compobj.c b/dlls/ole32/tests/compobj.c index 5ec5febb1a9..b4e12b38fe1 100644 --- a/dlls/ole32/tests/compobj.c +++ b/dlls/ole32/tests/compobj.c @@ -32,6 +32,7 @@ #include "urlmon.h" /* for CLSID_FileProtocol */ #include "dde.h" #include "cguid.h" +#include "comsvcs.h" #include "ctxtcall.h" @@ -69,6 +70,7 @@ DEFINE_EXPECT(PreInitialize); DEFINE_EXPECT(PostInitialize); DEFINE_EXPECT(PreUninitialize); DEFINE_EXPECT(PostUninitialize); +DEFINE_EXPECT(context_callback_func); /* functions that are not present on all versions of Windows */ static HRESULT (WINAPI * pCoGetObjectContext)(REFIID riid, LPVOID *ppv); @@ -2000,15 +2002,98 @@ static void test_CoFreeUnusedLibraries(void) CoUninitialize(); } +struct context_callback_arg +{ + IContextCallback *context_callback; + ULONG_PTR token; + BOOL is_mta; + GUID logical_thread_id; + BOOL todo_thread_id; +}; + +static HRESULT WINAPI context_callback_func(ComCallData *arg) +{ + struct context_callback_arg *ctx = (struct context_callback_arg *)arg; + ULONG_PTR token; + GUID thread_id; + HRESULT hr; + + CHECK_EXPECT(context_callback_func); + + hr = CoGetCurrentLogicalThreadId(&thread_id); + ok_ole_success(hr, "CoGetCurrentLgoicalThreadId"); + todo_wine_if(ctx->todo_thread_id) ok(IsEqualIID(&thread_id, &ctx->logical_thread_id), + "thread_id = %s\n", wine_dbgstr_guid(&thread_id)); + + hr = pCoGetContextToken(&token); + ok_ole_success(hr, "CoGetContextToken"); + ok(token == ctx->token, "executed in different context\n"); + return S_FALSE; +} + +static DWORD WINAPI context_callback_thread(void *arg) +{ + struct context_callback_arg *ctx = arg; + HRESULT hr; + GUID id; + + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = CoGetCurrentLogicalThreadId(&id); + ok_ole_success(hr, "CoGetCurrentLogicalThreadId"); + hr = IContextCallback_QueryInterface(ctx->context_callback, &IID_IObjContext, (void **)&ctx->token); + ok_ole_success(hr, "IContextCallback_QueryInterface"); + IObjContext_Release((IObjContext *)ctx->token); + + SET_EXPECT(context_callback_func); + ctx->logical_thread_id = id; + /* TODO: native calls the callback in current thread after temporarily converting it to MTA */ + if (ctx->is_mta) ctx->todo_thread_id = TRUE; + hr = IContextCallback_ContextCallback(ctx->context_callback, context_callback_func, + (ComCallData *)ctx, &IID_IContextCallback, 2, NULL); + ctx->todo_thread_id = FALSE; + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + SET_EXPECT(context_callback_func); + ctx->logical_thread_id = IID_IEnterActivityWithNoLock; + hr = IContextCallback_ContextCallback(ctx->context_callback, context_callback_func, + (ComCallData *)ctx, &IID_IEnterActivityWithNoLock, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + CoUninitialize(); + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + SET_EXPECT(context_callback_func); + ctx->logical_thread_id = id; + hr = IContextCallback_ContextCallback(ctx->context_callback, context_callback_func, + (ComCallData *)ctx, &IID_IContextCallback, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + SET_EXPECT(context_callback_func); + ctx->logical_thread_id = IID_IEnterActivityWithNoLock; + hr = IContextCallback_ContextCallback(ctx->context_callback, context_callback_func, + (ComCallData *)ctx, &IID_IEnterActivityWithNoLock, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + CoUninitialize(); + return 0; +} + static void test_CoGetObjectContext(void) { HRESULT hr; ULONG refs; IComThreadingInfo *pComThreadingInfo, *threadinginfo2; + struct context_callback_arg callback_arg; IContextCallback *pContextCallback; - IObjContext *pObjContext; APTTYPE apttype; THDTYPE thdtype; + HANDLE thread; GUID id, id2; if (!pCoGetObjectContext) @@ -2073,6 +2158,50 @@ static void test_CoGetObjectContext(void) hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback); ok_ole_success(hr, "CoGetObjectContext(ContextCallback)"); + callback_arg.context_callback = pContextCallback; + hr = pCoGetObjectContext(&IID_IObjContext, (void **)&callback_arg.token); + ok_ole_success(hr, "CoGetObjectContext"); + IObjContext_Release((IObjContext *)callback_arg.token); + callback_arg.is_mta = FALSE; + callback_arg.logical_thread_id = id2; + callback_arg.todo_thread_id = FALSE; + + SET_EXPECT(context_callback_func); + hr = IContextCallback_ContextCallback(pContextCallback, context_callback_func, + (ComCallData *)&callback_arg, &IID_IContextCallback, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + SET_EXPECT(context_callback_func); + callback_arg.logical_thread_id = IID_IEnterActivityWithNoLock; + hr = IContextCallback_ContextCallback(pContextCallback, context_callback_func, + (ComCallData *)&callback_arg, &IID_IEnterActivityWithNoLock, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + thread = CreateThread(NULL, 0, context_callback_thread, &callback_arg, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + while (1) + { + MSG msg; + + switch(MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLPOSTMESSAGE)) + { + case WAIT_OBJECT_0: + break; + case WAIT_OBJECT_0 + 1: + while (PeekMessageA(&msg, 0, 0, 0, PM_REMOVE)) + DispatchMessageA(&msg); + continue; + default: + ok(0, "MsgWaitForMultipleObjects failed\n"); + break; + } + + break; + } + CloseHandle(thread); + refs = IContextCallback_Release(pContextCallback); ok(refs == 0, "pContextCallback should have 0 refs instead of %ld refs\n", refs); @@ -2097,14 +2226,34 @@ static void test_CoGetObjectContext(void) hr = pCoGetObjectContext(&IID_IContextCallback, (void **)&pContextCallback); ok_ole_success(hr, "CoGetObjectContext(ContextCallback)"); - refs = IContextCallback_Release(pContextCallback); - ok(refs == 0, "pContextCallback should have 0 refs instead of %ld refs\n", refs); - - hr = pCoGetObjectContext(&IID_IObjContext, (void **)&pObjContext); + callback_arg.context_callback = pContextCallback; + hr = pCoGetObjectContext(&IID_IObjContext, (void **)&callback_arg.token); ok_ole_success(hr, "CoGetObjectContext"); + IObjContext_Release((IObjContext *)callback_arg.token); + callback_arg.is_mta = TRUE; + callback_arg.logical_thread_id = id2; + callback_arg.todo_thread_id = FALSE; + + SET_EXPECT(context_callback_func); + hr = IContextCallback_ContextCallback(pContextCallback, context_callback_func, + (ComCallData *)&callback_arg, &IID_IContextCallback, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + SET_EXPECT(context_callback_func); + callback_arg.logical_thread_id = IID_IEnterActivityWithNoLock; + hr = IContextCallback_ContextCallback(pContextCallback, context_callback_func, + (ComCallData *)&callback_arg, &IID_IEnterActivityWithNoLock, 2, NULL); + CHECK_CALLED(context_callback_func, 1); + ok(hr == S_FALSE, "got 0x%08lx\n", hr); + + thread = CreateThread(NULL, 0, context_callback_thread, &callback_arg, 0, NULL); + ok(thread != NULL, "CreateThread failed\n"); + WaitForSingleObject(thread, INFINITE); + CloseHandle(thread); - refs = IObjContext_Release(pObjContext); - ok(refs == 0, "pObjContext should have 0 refs instead of %ld refs\n", refs); + refs = IContextCallback_Release(pContextCallback); + ok(refs == 0, "pContextCallback should have 0 refs instead of %ld refs\n", refs); CoUninitialize(); } -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/10995
This merge request was approved by Huw Davies. -- https://gitlab.winehq.org/wine/wine/-/merge_requests/10995
participants (3)
-
Huw Davies (@huw) -
Piotr Caban -
Piotr Caban (@piotr)