From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 26 ++++---- dlls/uiautomationcore/uia_com_client.c | 72 +++++++++++++++++++++- 2 files changed, 83 insertions(+), 15 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 0aff7a8ad24..b71d89bba45 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -13089,11 +13089,11 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati */ hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, NULL, TreeScope_SubTree, NULL, &AutomationEventHandler.IUIAutomationEventHandler_iface); - todo_wine ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem, TreeScope_SubTree, NULL, NULL); - todo_wine ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr);
/* * Passing in a NULL element to this method results in an access violation @@ -13118,21 +13118,21 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati */ hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_AutomationFocusChangedEventId, elem, TreeScope_SubTree, NULL, &AutomationEventHandler.IUIAutomationEventHandler_iface); - todo_wine ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
/* Windows 11 queries the HWND for the element when adding a new handler. */ set_uia_hwnd_expects(3, 2, 2, 3, 0); /* All other event IDs are fine, only focus events are blocked. */ hr = IUIAutomation_AddAutomationEventHandler(uia_iface, 1, elem, TreeScope_SubTree, NULL, &AutomationEventHandler.IUIAutomationEventHandler_iface); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); check_uia_hwnd_expects_at_most(3, 2, 2, 3, 0);
hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, 1, elem, &AutomationEventHandler.IUIAutomationEventHandler_iface); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + todo_wine ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
/* * Test event raising behavior. @@ -13140,8 +13140,8 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati set_uia_hwnd_expects(3, 2, 2, 3, 0); hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem, TreeScope_SubTree, NULL, &AutomationEventHandler.IUIAutomationEventHandler_iface); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); check_uia_hwnd_expects_at_most(3, 2, 2, 3, 0);
/* Same behavior as HUIAEVENTs, events are matched by runtime ID. */ @@ -13184,7 +13184,7 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem, &AutomationEventHandler.IUIAutomationEventHandler_iface); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + todo_wine ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
VariantInit(&v); initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); @@ -13207,18 +13207,18 @@ static void test_IUIAutomationEventHandler(IUIAutomation *uia_iface, IUIAutomati */ hr = IUIAutomation_AddAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem2, TreeScope_SubTree, NULL, &AutomationEventHandler.IUIAutomationEventHandler_iface); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
/* No removal will occur due to a lack of a runtime ID to match. */ hr = IUIAutomation_RemoveAutomationEventHandler(uia_iface, UIA_LiveRegionChangedEventId, elem2, &AutomationEventHandler.IUIAutomationEventHandler_iface); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - todo_wine ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + ok(AutomationEventHandler.ref > 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
hr = IUIAutomation_RemoveAllEventHandlers(uia_iface); todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref); + todo_wine ok(AutomationEventHandler.ref == 1, "Unexpected refcnt %ld\n", AutomationEventHandler.ref);
IUIAutomationElement_Release(elem2); } diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 919936c7acb..63abc3cb931 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -898,6 +898,57 @@ static HRESULT get_uia_cache_request_struct_from_iface(IUIAutomationCacheRequest return S_OK; }
+/* + * COM API UI Automation event related functions. + */ +static struct uia_com_event_handlers +{ + struct list handler_list; + + LONG handler_count; +} com_event_handlers; + +static CRITICAL_SECTION com_event_handlers_cs; +static CRITICAL_SECTION_DEBUG com_event_handlers_cs_debug = +{ + 0, 0, &com_event_handlers_cs, + { &com_event_handlers_cs_debug.ProcessLocksList, &com_event_handlers_cs_debug.ProcessLocksList }, + 0, 0, { (DWORD_PTR)(__FILE__ ": com_event_handlers_cs") } +}; +static CRITICAL_SECTION com_event_handlers_cs = { &com_event_handlers_cs_debug, -1, 0, 0, 0, 0 }; + +struct uia_com_event { + IUnknown *handler_iface; + int event_id; + + struct list event_handler_list_entry; +}; + +static HRESULT uia_event_handlers_add_handler(IUnknown *handler_iface, int event_id) +{ + struct uia_com_event *event; + HRESULT hr = S_OK; + + if (!(event = heap_alloc_zero(sizeof(*event)))) + return E_OUTOFMEMORY; + + event->handler_iface = handler_iface; + IUnknown_AddRef(handler_iface); + event->event_id = event_id; + + EnterCriticalSection(&com_event_handlers_cs); + + if (!com_event_handlers.handler_count) + list_init(&com_event_handlers.handler_list); + + list_add_tail(&com_event_handlers.handler_list, &event->event_handler_list_entry); + com_event_handlers.handler_count++; + + LeaveCriticalSection(&com_event_handlers_cs); + + return hr; +} + /* * IUIAutomationElementArray interface. */ @@ -3052,8 +3103,25 @@ static HRESULT WINAPI uia_iface_AddAutomationEventHandler(IUIAutomation6 *iface, IUIAutomationElement *elem, enum TreeScope scope, IUIAutomationCacheRequest *cache_req, IUIAutomationEventHandler *handler) { - FIXME("%p, %d, %p, %#x, %p, %p: stub\n", iface, event_id, elem, scope, cache_req, handler); - return E_NOTIMPL; + IUnknown *handler_iface; + HRESULT hr; + + TRACE("%p, %d, %p, %#x, %p, %p\n", iface, event_id, elem, scope, cache_req, handler); + + if (!elem || !handler) + return E_POINTER; + + if (event_id == UIA_AutomationFocusChangedEventId) + return E_INVALIDARG; + + hr = IUIAutomationEventHandler_QueryInterface(handler, &IID_IUnknown, (void **)&handler_iface); + if (FAILED(hr)) + return hr; + + hr = uia_event_handlers_add_handler(handler_iface, event_id); + IUnknown_Release(handler_iface); + + return hr; }
static HRESULT WINAPI uia_iface_RemoveAutomationEventHandler(IUIAutomation6 *iface, EVENTID event_id,