From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 33 +++----- dlls/uiautomationcore/uia_event.c | 91 ++++++++++++++++++---- 2 files changed, 90 insertions(+), 34 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 2a56bf8cec7..e386db246a3 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1766,15 +1766,6 @@ static struct prov_method_sequence *sequence; { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \
-#define NODE_CREATE_SEQ_TODO(prov) \ - { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, \ - /* Win10v1507 and below call this. */ \ - { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ - { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, \ - { prov , PROV_GET_PROPERTY_VALUE, METHOD_TODO }, \ - { prov , FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ \ - { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ - #define NODE_CREATE_SEQ_OPTIONAL(prov) \ { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, \ /* Win10v1507 and below call this. */ \ @@ -16727,9 +16718,9 @@ static const struct prov_method_sequence win_event_handler_seq[] = { { &Provider_hwnd2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_nc2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, { &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, - NODE_CREATE_SEQ_TODO(&Provider_child), - { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_TODO }, - { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
@@ -16862,7 +16853,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para method_sequences_enabled = TRUE; set_uia_hwnd_expects(1, 1, 1, 4, 3); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); ok_method_sequence(win_event_handler_seq, "win_event_handler_seq"); check_uia_hwnd_expects_at_least(1, TRUE, 1, FALSE, 1, FALSE, 1, FALSE, 1, FALSE); method_sequences_enabled = FALSE; @@ -16909,7 +16900,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para set_uia_hwnd_expects(0, 1, 1, 2, 0); SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 4); /* Only sent 4 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE); CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
@@ -16955,7 +16946,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para */ set_uia_hwnd_expects(1, 1, 1, 4, 3); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects_at_least(1, TRUE, 1, FALSE, 1, FALSE, 1, FALSE, 1, FALSE);
/* Raise a WinEvent on our test child HWND, both event callbacks invoked. */ @@ -16965,7 +16956,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para set_uia_hwnd_expects(0, 2, 2, 4, 0); SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 8); /* Only sent 8 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, - ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); + ARRAY_SIZE(event_handles), TRUE, TRUE, FALSE); CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
@@ -16985,7 +16976,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para set_uia_hwnd_expects(0, 2, 2, 0, 0); SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 12); /* Only sent 12 times on Win11. */ test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, tmp_hwnd2, OBJID_WINDOW, CHILDID_SELF, event_handles, - ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); + ARRAY_SIZE(event_handles), TRUE, TRUE, FALSE); CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 0, FALSE, 0, FALSE);
@@ -17033,7 +17024,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para UIA_AutomationFocusChangedEventId); set_uia_hwnd_expects(0, 1, 1, 0, 0); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
/* @@ -17074,14 +17065,14 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para /* WinEvent handled. */ set_uia_hwnd_expects(1, 1, 1, 2, 1); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects(1, TRUE, 1, FALSE, 1, FALSE, 2, FALSE, 1, FALSE);
/* Child HWNDs of our test window are handled as well. */ SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); set_uia_hwnd_expects(0, 1, 1, 1, 0); test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE);
hr = UiaRemoveEvent(event); @@ -17119,7 +17110,7 @@ skip_win_event_hwnd_filter_test: /* WinEvent handled by default MSAA proxy provider. */ set_uia_hwnd_expects(1, 1, 1, 4, 5); test_uia_event_win_event_mapping(EVENT_SYSTEM_ALERT, hwnd[0], OBJID_CLIENT, 2, event_handles, - 1, TRUE, FALSE, TRUE); + 1, TRUE, FALSE, FALSE); check_uia_hwnd_expects_at_most(1, 1, 1, 4, 5);
hr = UiaRemoveEvent(event); diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 0b0ea86decf..395b20e0537 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -322,6 +322,32 @@ static void uia_event_args_release(struct uia_event_args *args) free(args); }
+struct event_sink_event +{ + struct list event_sink_list_entry; + + IRawElementProviderSimple *elprov; + struct uia_event_args *args; +}; + +static HRESULT uia_event_sink_list_add_event(struct list *sink_events, IRawElementProviderSimple *elprov, + struct uia_event_args *args) +{ + struct event_sink_event *sink_event = calloc(1, sizeof(*sink_event)); + + if (!sink_event) + return E_OUTOFMEMORY; + + IRawElementProviderSimple_AddRef(elprov); + InterlockedIncrement(&args->ref); + + sink_event->elprov = elprov; + sink_event->args = args; + list_add_tail(sink_events, &sink_event->event_sink_list_entry); + + return S_OK; +} + /* * IProxyProviderWinEventSink interface implementation. */ @@ -331,6 +357,8 @@ struct uia_proxy_win_event_sink {
int event_id; IUnknown *marshal; + LONG sink_defunct; + struct list sink_events; };
static inline struct uia_proxy_win_event_sink *impl_from_IProxyProviderWinEventSink(IProxyProviderWinEventSink *iface) @@ -373,6 +401,7 @@ static ULONG WINAPI uia_proxy_win_event_sink_Release(IProxyProviderWinEventSink
if (!ref) { + assert(list_empty(&sink->sink_events)); IUnknown_Release(sink->marshal); free(sink); } @@ -390,8 +419,23 @@ static HRESULT WINAPI uia_proxy_win_event_sink_AddAutomationPropertyChangedEvent static HRESULT WINAPI uia_proxy_win_event_sink_AddAutomationEvent(IProxyProviderWinEventSink *iface, IRawElementProviderSimple *elprov, EVENTID event_id) { - FIXME("%p, %p, %d: stub\n", iface, elprov, event_id); - return S_OK; + struct uia_proxy_win_event_sink *sink = impl_from_IProxyProviderWinEventSink(iface); + struct uia_event_args *args; + HRESULT hr = S_OK; + + TRACE("%p, %p, %d\n", iface, elprov, event_id); + + if (event_id != sink->event_id) + return S_OK; + + args = create_uia_event_args(uia_event_info_from_id(event_id)); + if (!args) + return E_OUTOFMEMORY; + + if (InterlockedCompareExchange(&sink->sink_defunct, 0, 0) == 0) + hr = uia_event_sink_list_add_event(&sink->sink_events, elprov, args); + uia_event_args_release(args); + return hr; }
static HRESULT WINAPI uia_proxy_win_event_sink_AddStructureChangedEvent(IProxyProviderWinEventSink *iface, @@ -422,6 +466,7 @@ static HRESULT create_proxy_win_event_sink(struct uia_proxy_win_event_sink **out sink->IProxyProviderWinEventSink_iface.lpVtbl = &uia_proxy_event_sink_vtbl; sink->ref = 1; sink->event_id = event_id; + list_init(&sink->sink_events);
hr = CoCreateFreeThreadedMarshaler((IUnknown *)&sink->IProxyProviderWinEventSink_iface, &sink->marshal); if (FAILED(hr)) @@ -684,9 +729,21 @@ static HRESULT create_msaa_provider_from_hwnd(HWND hwnd, int in_child_id, IRawEl return S_OK; }
+struct uia_elprov_event_data +{ + IRawElementProviderSimple *elprov; + struct uia_event_args *args; + BOOL clientside_only; + + SAFEARRAY *rt_id; + HUIANODE node; +}; + +static HRESULT uia_raise_elprov_event_callback(struct uia_event *event, void *data); static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *data) { struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)data; + struct event_sink_event *sink_event, *sink_event2; struct uia_proxy_win_event_sink *sink; IRawElementProviderSimple *elprov; struct uia_node *node_data; @@ -727,10 +784,28 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da { hr = respond_to_win_event_on_node_provider((IWineUiaNode *)node, i, win_event->event_id, win_event->hwnd, win_event->obj_id, win_event->child_id, &sink->IProxyProviderWinEventSink_iface); - if (FAILED(hr)) + if (FAILED(hr) || !list_empty(&sink->sink_events)) break; }
+ InterlockedIncrement(&sink->sink_defunct); + LIST_FOR_EACH_ENTRY_SAFE(sink_event, sink_event2, &sink->sink_events, struct event_sink_event, event_sink_list_entry) + { + struct uia_elprov_event_data event_data = { sink_event->elprov, sink_event->args, TRUE }; + list_remove(&sink_event->event_sink_list_entry); + + hr = uia_raise_elprov_event_callback(event, (void *)&event_data); + if (FAILED(hr)) + WARN("uia_raise_elprov_event_callback failed with hr %#lx\n", hr); + + UiaNodeRelease(event_data.node); + SafeArrayDestroy(event_data.rt_id); + + IRawElementProviderSimple_Release(sink_event->elprov); + uia_event_args_release(sink_event->args); + free(sink_event); + } + IProxyProviderWinEventSink_Release(&sink->IProxyProviderWinEventSink_iface); }
@@ -1806,16 +1881,6 @@ static HRESULT uia_event_check_match(HUIANODE node, HUIANODE nav_start_node, SAF return hr; }
-struct uia_elprov_event_data -{ - IRawElementProviderSimple *elprov; - struct uia_event_args *args; - BOOL clientside_only; - - SAFEARRAY *rt_id; - HUIANODE node; -}; - static HRESULT uia_raise_elprov_event_callback(struct uia_event *event, void *data) { struct uia_elprov_event_data *event_data = (struct uia_elprov_event_data *)data;