Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/Makefile.in | 1 + dlls/uiautomationcore/uia_main.c | 131 +++++++++++++++++++++++++++++- 2 files changed, 130 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..01d5ba67a88 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -16,12 +16,134 @@ * 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_obj_marshal_wrapper +{ + IUnknown IUnknown_iface; + LONG refcount; + + IUnknown *marshaler; + IUnknown *marshal_object; +}; + +static struct uia_rsrv_obj_marshal_wrapper *impl_uia_rsrv_obj_marshal_wrapper_from_IUnknown(IUnknown *iface) +{ + return CONTAINING_RECORD(iface, struct uia_rsrv_obj_marshal_wrapper, IUnknown_iface); +} + +static HRESULT WINAPI uia_rsrv_obj_marshal_wrapper_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + struct uia_rsrv_obj_marshal_wrapper *wrapper = impl_uia_rsrv_obj_marshal_wrapper_from_IUnknown(iface); + return IUnknown_QueryInterface(wrapper->marshal_object, riid, ppv); +} + +static ULONG WINAPI uia_rsrv_obj_marshal_wrapper_AddRef(IUnknown *iface) +{ + struct uia_rsrv_obj_marshal_wrapper *wrapper = impl_uia_rsrv_obj_marshal_wrapper_from_IUnknown(iface); + ULONG refcount = InterlockedIncrement(&wrapper->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI uia_rsrv_obj_marshal_wrapper_Release(IUnknown *iface) +{ + struct uia_rsrv_obj_marshal_wrapper *wrapper = impl_uia_rsrv_obj_marshal_wrapper_from_IUnknown(iface); + ULONG refcount = InterlockedDecrement(&wrapper->refcount); + + TRACE("%p, refcount %d\n", iface, refcount); + if (!refcount) + { + IUnknown_Release(wrapper->marshaler); + heap_free(wrapper); + } + + return refcount; +} + +static const IUnknownVtbl uia_rsrv_obj_marshal_wrapper_vtbl = { + uia_rsrv_obj_marshal_wrapper_QueryInterface, + uia_rsrv_obj_marshal_wrapper_AddRef, + uia_rsrv_obj_marshal_wrapper_Release, +}; + +/* + * When passing the ReservedNotSupportedValue/ReservedMixedAttributeValue + * interface pointers across apartments within the same process, create a free + * threaded marshaler so that the pointer value is preserved. + */ +static HRESULT uia_rsrv_obj_create_marshal_wrapper(IUnknown *reserved, void **ppv) +{ + struct uia_rsrv_obj_marshal_wrapper *wrapper; + HRESULT hr; + + TRACE("%p, %p\n", reserved, ppv); + + wrapper = heap_alloc(sizeof(*wrapper)); + if (!wrapper) + return E_OUTOFMEMORY; + + wrapper->IUnknown_iface.lpVtbl = &uia_rsrv_obj_marshal_wrapper_vtbl; + wrapper->marshal_object = reserved; + wrapper->refcount = 1; + + if (FAILED(hr = CoCreateFreeThreadedMarshaler(&wrapper->IUnknown_iface, &wrapper->marshaler))) + { + heap_free(wrapper); + return hr; + } + + hr = IUnknown_QueryInterface(wrapper->marshaler, &IID_IMarshal, ppv); + IUnknown_Release(&wrapper->IUnknown_iface); + + return hr; +} + +/* + * 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)) + return uia_rsrv_obj_create_marshal_wrapper(iface, ppv); + 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 +168,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; }
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_main.c | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 01d5ba67a88..7966e1cf730 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -144,6 +144,41 @@ static const IUnknownVtbl uia_reserved_ns_vtbl = {
static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
+/* + * UiaReservedMixedAttribute object. + */ +static HRESULT WINAPI uia_reserved_ma_QueryInterface(IUnknown *iface, + REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IMarshal)) + return uia_rsrv_obj_create_marshal_wrapper(iface, ppv); + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI uia_reserved_ma_AddRef(IUnknown *iface) +{ + return 1; +} + +static ULONG WINAPI uia_reserved_ma_Release(IUnknown *iface) +{ + return 1; +} + +static const IUnknownVtbl uia_reserved_ma_vtbl = { + uia_reserved_ma_QueryInterface, + uia_reserved_ma_AddRef, + uia_reserved_ma_Release, +}; + +static IUnknown uia_reserved_ma_iface = {&uia_reserved_ma_vtbl}; + /*********************************************************************** * UiaClientsAreListening (uiautomationcore.@) */ @@ -158,8 +193,13 @@ BOOL WINAPI UiaClientsAreListening(void) */ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) { - FIXME("(%p) stub!\n", value); - *value = NULL; + TRACE("(%p)\n", value); + + if (!value) + return E_INVALIDARG; + + *value = &uia_reserved_ma_iface; + return S_OK; }
On 10/28/21 10:50 PM, Connor McAdams wrote:
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/uiautomationcore/uia_main.c | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 01d5ba67a88..7966e1cf730 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -144,6 +144,41 @@ static const IUnknownVtbl uia_reserved_ns_vtbl = {
static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
+/*
- UiaReservedMixedAttribute object.
- */
+static HRESULT WINAPI uia_reserved_ma_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- *ppv = NULL;
- if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
- else if (IsEqualIID(riid, &IID_IMarshal))
return uia_rsrv_obj_create_marshal_wrapper(iface, ppv);
- else
return E_NOINTERFACE;
- return S_OK;
+}
+static ULONG WINAPI uia_reserved_ma_AddRef(IUnknown *iface) +{
- return 1;
+}
+static ULONG WINAPI uia_reserved_ma_Release(IUnknown *iface) +{
- return 1;
+}
+static const IUnknownVtbl uia_reserved_ma_vtbl = {
- uia_reserved_ma_QueryInterface,
- uia_reserved_ma_AddRef,
- uia_reserved_ma_Release,
+};
Why do you need to duplicate methods and vtable, if it's identical to *_reserved_ns_* ?
+static IUnknown uia_reserved_ma_iface = {&uia_reserved_ma_vtbl};
/***********************************************************************
UiaClientsAreListening (uiautomationcore.@)
*/ @@ -158,8 +193,13 @@ BOOL WINAPI UiaClientsAreListening(void) */ HRESULT WINAPI UiaGetReservedMixedAttributeValue(IUnknown **value) {
- FIXME("(%p) stub!\n", value);
- *value = NULL;
- TRACE("(%p)\n", value);
- if (!value)
return E_INVALIDARG;
- *value = &uia_reserved_ma_iface;
- return S_OK;
}
On Fri, Oct 29, 2021 at 03:45:27PM +0300, Nikolay Sivov wrote:
On 10/28/21 10:50 PM, Connor McAdams wrote:
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
dlls/uiautomationcore/uia_main.c | 44 ++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index 01d5ba67a88..7966e1cf730 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -144,6 +144,41 @@ static const IUnknownVtbl uia_reserved_ns_vtbl = {
static IUnknown uia_reserved_ns_iface = {&uia_reserved_ns_vtbl};
+/*
- UiaReservedMixedAttribute object.
- */
+static HRESULT WINAPI uia_reserved_ma_QueryInterface(IUnknown *iface,
REFIID riid, void **ppv)
+{
- *ppv = NULL;
- if (IsEqualIID(riid, &IID_IUnknown))
*ppv = iface;
- else if (IsEqualIID(riid, &IID_IMarshal))
return uia_rsrv_obj_create_marshal_wrapper(iface, ppv);
- else
return E_NOINTERFACE;
- return S_OK;
+}
+static ULONG WINAPI uia_reserved_ma_AddRef(IUnknown *iface) +{
- return 1;
+}
+static ULONG WINAPI uia_reserved_ma_Release(IUnknown *iface) +{
- return 1;
+}
+static const IUnknownVtbl uia_reserved_ma_vtbl = {
- uia_reserved_ma_QueryInterface,
- uia_reserved_ma_AddRef,
- uia_reserved_ma_Release,
+};
Why do you need to duplicate methods and vtable, if it's identical to *_reserved_ns_* ?
I guess I really don't, I was thinking more in terms of comparing lpVtbl values, but since what actually gets compared is the pointer value of the IUnknown, they can have identical vtables. I'll fix this and send a new version.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/Makefile.in | 2 +- dlls/uiautomationcore/tests/uiautomation.c | 133 +++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/tests/Makefile.in b/dlls/uiautomationcore/tests/Makefile.in index c39b062b6fd..1d08e19093f 100644 --- a/dlls/uiautomationcore/tests/Makefile.in +++ b/dlls/uiautomationcore/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = uiautomationcore.dll -IMPORTS = uiautomationcore user32 +IMPORTS = uiautomationcore user32 ole32
C_SRCS = \ uiautomation.c diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index cbcba1af294..52a6648dad2 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -86,7 +86,140 @@ if (hr == S_OK) UnregisterClassA("HostProviderFromHwnd class", NULL); }
+static DWORD WINAPI uia_reserved_val_iface_marshal_thread(LPVOID param) +{ + IStream **stream = param; + IUnknown *unk_ns, *unk_ns2, *unk_ma, *unk_ma2; + HRESULT hr; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + + hr = CoGetInterfaceAndReleaseStream(stream[0], &IID_IUnknown, (void **)&unk_ns); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = CoGetInterfaceAndReleaseStream(stream[1], &IID_IUnknown, (void **)&unk_ma); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedNotSupportedValue(&unk_ns2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + ok(unk_ns2 == unk_ns, "UiaGetReservedNotSupported pointer mismatch, unk_ns2 %p, unk_ns %p\n", unk_ns2, unk_ns); + ok(unk_ma2 == unk_ma, "UiaGetReservedMixedAttribute pointer mismatch, unk_ma2 %p, unk_ma %p\n", unk_ma2, unk_ma); + + CoUninitialize(); + + return 0; +} + +static void test_uia_reserved_value_ifaces(void) +{ + IUnknown *unk_ns, *unk_ns2, *unk_ma, *unk_ma2; + IStream *stream[2]; + IMarshal *marshal; + HANDLE thread; + ULONG refcnt; + HRESULT hr; + + /* ReservedNotSupportedValue. */ + hr = UiaGetReservedNotSupportedValue(NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedNotSupportedValue(&unk_ns); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ns != NULL, "UiaGetReservedNotSupportedValue returned NULL interface.\n"); + + refcnt = IUnknown_AddRef(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_AddRef(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_Release(unk_ns); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + hr = UiaGetReservedNotSupportedValue(&unk_ns2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ns2 != NULL, "UiaGetReservedNotSupportedValue returned NULL interface."); + ok(unk_ns2 == unk_ns, "UiaGetReservedNotSupported pointer mismatch, unk_ns2 %p, unk_ns %p\n", unk_ns2, unk_ns); + + marshal = NULL; + hr = IUnknown_QueryInterface(unk_ns, &IID_IMarshal, (void **)&marshal); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(marshal != NULL, "Failed to get IMarshal interface.\n"); + + refcnt = IMarshal_AddRef(marshal); + ok(refcnt == 2, "Expected refcnt %d, got %d\n", 2, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 0, "Expected refcnt %d, got %d\n", 0, refcnt); + + /* ReservedMixedAttributeValue. */ + hr = UiaGetReservedMixedAttributeValue(NULL); + ok(hr == E_INVALIDARG, "Unexpected hr %#x.\n", hr); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ma != NULL, "UiaGetReservedMixedAttributeValue returned NULL interface."); + + refcnt = IUnknown_AddRef(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_AddRef(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IUnknown_Release(unk_ma); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + hr = UiaGetReservedMixedAttributeValue(&unk_ma2); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(unk_ma2 != NULL, "UiaGetReservedMixedAttributeValue returned NULL interface."); + ok(unk_ma2 == unk_ma, "UiaGetReservedMixedAttribute pointer mismatch, unk_ma2 %p, unk_ma %p\n", unk_ma2, unk_ma); + + marshal = NULL; + hr = IUnknown_QueryInterface(unk_ma, &IID_IMarshal, (void **)&marshal); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + ok(marshal != NULL, "Failed to get IMarshal interface.\n"); + + refcnt = IMarshal_AddRef(marshal); + ok(refcnt == 2, "Expected refcnt %d, got %d\n", 2, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 1, "Expected refcnt %d, got %d\n", 1, refcnt); + + refcnt = IMarshal_Release(marshal); + ok(refcnt == 0, "Expected refcnt %d, got %d\n", 0, refcnt); + + /* Test cross-thread marshaling behavior. */ + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, unk_ns, &stream[0]); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + hr = CoMarshalInterThreadInterfaceInStream(&IID_IUnknown, unk_ma, &stream[1]); + ok(hr == S_OK, "Unexpected hr %#x.\n", hr); + + thread = CreateThread(NULL, 0, uia_reserved_val_iface_marshal_thread, (void *)stream, 0, NULL); + while (MsgWaitForMultipleObjects(1, &thread, FALSE, INFINITE, QS_ALLINPUT) != WAIT_OBJECT_0) + { + MSG msg; + while(PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessageW(&msg); + } + } + CloseHandle(thread); + + CoUninitialize(); +} + START_TEST(uiautomation) { test_UiaHostProviderFromHwnd(); + test_uia_reserved_value_ifaces(); }