Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 196 +++++++++++++++++++++++++++++- 2 files changed, 195 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index 71ea7b99c94..5a72ea144c4 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -1,5 +1,6 @@ MODULE = uiautomationcore.dll IMPORTLIB = uiautomationcore +IMPORTS = uuid ole32
EXTRADLLFLAGS = -Wb,--prefer-native
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 2dada95af80..e51a4b4d555 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,12 +16,199 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */
+#define COBJMACROS + #include "uiautomation.h"
#include "wine/debug.h" +#include "wine/heap.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+struct uia_rsrv_ftmarshaler +{ + IMarshal IMarshal_iface; + + IUnknown *inner_unk; + IMarshal *marshal; +}; + +/* + * Create a custom proxy IMarshal, so that IMarshal::Release actually releases + * the interface. + */ +static struct uia_rsrv_ftmarshaler *impl_uia_rsrv_ft_from_IMarshal(IMarshal *iface) +{ + return CONTAINING_RECORD(iface, struct uia_rsrv_ftmarshaler, IMarshal_iface); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_QueryInterface(IMarshal *iface, REFIID riid, void **obj) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + + TRACE("%p, %s, %p\n", iface, debugstr_guid(riid), obj); + + return IMarshal_QueryInterface(marshaler->marshal, riid, obj); +} + +static ULONG WINAPI uia_rsrv_ftmarshaler_AddRef(IMarshal *iface) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + ULONG ref = IUnknown_AddRef(marshaler->inner_unk); + + TRACE("%p, ref %d\n", iface, ref); + + return ref; +} + +static ULONG WINAPI uia_rsrv_ftmarshaler_Release(IMarshal *iface) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + ULONG ref = IUnknown_Release(marshaler->inner_unk); + + TRACE("%p, ref %d\n", iface, ref); + + if (!ref) + heap_free(marshaler); + + return ref; +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_GetUnmarshalClass(IMarshal *iface, REFIID riid, void *pv, + DWORD dest_context, void *pvDestContext, DWORD mshlflags, CLSID *clsid) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, clsid); + return IMarshal_GetUnmarshalClass(marshaler->marshal, riid, pv, dest_context, pvDestContext, mshlflags, clsid); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_GetMarshalSizeMax(IMarshal *iface, REFIID riid, void *pv, + DWORD dest_context, void *pvDestContext, DWORD mshlflags, DWORD *size) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("%s, %p, %#x, %p, %#x, %p\n", debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags, size); + return IMarshal_GetMarshalSizeMax(marshaler->marshal, riid, pv, dest_context, pvDestContext, mshlflags, size); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_MarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, + void *pv, DWORD dest_context, void *pvDestContext, DWORD mshlflags) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("%p, %s, %p, %#x, %p, %#x\n", stream, debugstr_guid(riid), pv, dest_context, pvDestContext, mshlflags); + return IMarshal_MarshalInterface(marshaler->marshal, stream, riid, pv, dest_context, pvDestContext, mshlflags); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_UnmarshalInterface(IMarshal *iface, IStream *stream, REFIID riid, void **ppv) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("%p, %s, %p\n", stream, debugstr_guid(riid), ppv); + return IMarshal_UnmarshalInterface(marshaler->marshal, stream, riid, ppv); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_ReleaseMarshalData(IMarshal *iface, IStream *stream) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("%p\n", stream); + return IMarshal_ReleaseMarshalData(marshaler->marshal, stream); +} + +static HRESULT WINAPI uia_rsrv_ftmarshaler_DisconnectObject(IMarshal *iface, DWORD reserved) +{ + struct uia_rsrv_ftmarshaler *marshaler = impl_uia_rsrv_ft_from_IMarshal(iface); + TRACE("\n"); + return IMarshal_DisconnectObject(marshaler->marshal, reserved); +} + +static const IMarshalVtbl uia_rsrv_ftmarshaler_vtbl = +{ + uia_rsrv_ftmarshaler_QueryInterface, + uia_rsrv_ftmarshaler_AddRef, + uia_rsrv_ftmarshaler_Release, + uia_rsrv_ftmarshaler_GetUnmarshalClass, + uia_rsrv_ftmarshaler_GetMarshalSizeMax, + uia_rsrv_ftmarshaler_MarshalInterface, + uia_rsrv_ftmarshaler_UnmarshalInterface, + uia_rsrv_ftmarshaler_ReleaseMarshalData, + uia_rsrv_ftmarshaler_DisconnectObject +}; + +/* + * When passing the ReservedNotSupportedValue/ReservedMixedAttributeValue + * interface pointers across apartments within the same process, use the + * free threaded marshaler to preserve the pointer value. Wrap the IMarshal + * interface received by CoCreateFreeThreadedMarshaler so that we can maintain + * our own reference count and release the object when it hits 0. + */ +static HRESULT uia_reserved_val_create_ftm(IUnknown *outer, IMarshal **marshaler) +{ + struct uia_rsrv_ftmarshaler *object; + IUnknown *ftm_unk; + HRESULT hr; + + TRACE("%p, %p\n", outer, marshaler); + + hr = CoCreateFreeThreadedMarshaler(outer, &ftm_unk); + if (FAILED(hr)) return hr; + + object = heap_alloc(sizeof(*object)); + if (!object) + { + IUnknown_Release(ftm_unk); + return E_OUTOFMEMORY; + } + + object->IMarshal_iface.lpVtbl = &uia_rsrv_ftmarshaler_vtbl; + object->inner_unk = ftm_unk; + hr = IUnknown_QueryInterface(ftm_unk, &IID_IMarshal, (void **)&object->marshal); + if (FAILED(hr)) + FIXME("Failed to QI for IMarshal.\n"); + + *marshaler = &object->IMarshal_iface; + + return S_OK; +} + +/* + * UiaReservedNotSupported object. + */ +static HRESULT WINAPI uia_reserved_ns_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IMarshal)) + { + IMarshal *ftm; + + if (FAILED(uia_reserved_val_create_ftm(iface, &ftm))) + return E_NOINTERFACE; + *ppv = ftm; + } + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI uia_reserved_ns_AddRef(IUnknown *iface) +{ + return 1; +} + +static ULONG WINAPI uia_reserved_ns_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl uia_reserved_ns_vtbl = { + uia_reserved_ns_QueryInterface, + uia_reserved_ns_AddRef, + uia_reserved_ns_Release, +}; + +static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl}; + /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ @@ -46,8 +233,13 @@ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) */ HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value) { - FIXME("(%p) stub!\n", value); - *value = NULL; + TRACE("(%p)\n", value); + + if (!value) + return E_INVALIDARG; + + *value = &uia_reserved_ns_iface; + return S_OK; }