From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 31 +++----- dlls/uiautomationcore/uia_client.c | 1 - dlls/uiautomationcore/uia_event.c | 85 +++++++++++++++++++--- dlls/uiautomationcore/uia_private.h | 2 + 4 files changed, 87 insertions(+), 32 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index f7afe254aed..4ad1ad17214 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1761,15 +1761,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. */ \ @@ -16719,9 +16710,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 } };
@@ -16854,7 +16845,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; @@ -16901,7 +16892,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);
@@ -16947,7 +16938,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. */ @@ -16957,7 +16948,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);
@@ -17000,7 +16991,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);
/* @@ -17041,14 +17032,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); @@ -17086,7 +17077,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_client.c b/dlls/uiautomationcore/uia_client.c index f50c739ae97..1ecb2b436d0 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1890,7 +1890,6 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT if (!prov->return_nested_node && SUCCEEDED(IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IProxyProviderWinEventHandler, (void **)&winevent_handler))) { - FIXME("MSAA to UIA event bridge currently unimplemented\n"); hr = uia_event_add_win_event_hwnd(event, prov->hwnd); if (FAILED(hr)) WARN("Failed to add hwnd for win_event, hr %#lx\n", hr); diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 97171e7bebc..f6e3cb430f0 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -555,11 +555,32 @@ static HRESULT create_msaa_provider_from_hwnd(HWND hwnd, int in_child_id, IRawEl return S_OK; }
+struct event_sink_event +{ + struct list event_sink_list_entry; + + IRawElementProviderSimple *elprov; + struct uia_event_args *args; +}; + +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; IRawElementProviderSimple *elprov; struct uia_node *node_data; + struct list sink_events; HUIANODE node; HRESULT hr; int i; @@ -592,6 +613,9 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da if (FAILED(hr)) return hr;
+ list_init(&sink_events); + event->u.clientside.sink_events = &sink_events; + node_data = impl_from_IWineUiaNode((IWineUiaNode *)node); for (i = 0; i < node_data->prov_count; i++) { @@ -599,8 +623,33 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da win_event->child_id, event); if (FAILED(hr)) break; + + if (!list_empty(&sink_events)) + break; + } + + LIST_FOR_EACH_ENTRY_SAFE(sink_event, sink_event2, &sink_events, struct event_sink_event, event_sink_list_entry) + { + list_remove(&sink_event->event_sink_list_entry); + + if (sink_event->args->simple_args.EventId == event->event_id) + { + struct uia_elprov_event_data event_data = { sink_event->elprov, sink_event->args, TRUE }; + + 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); }
+ event->u.clientside.sink_events = NULL; UiaNodeRelease(node); return S_OK; } @@ -1004,6 +1053,11 @@ static HRESULT create_uia_event(struct uia_event **out_event, LONG event_cookie, /* * IProxyProviderWinEventSink interface implementation for clientside events. */ +static inline struct uia_event *impl_from_ProxyEventSink(IProxyProviderWinEventSink *iface) +{ + return CONTAINING_RECORD(iface, struct uia_event, u.clientside.IProxyProviderWinEventSink_iface); +} + static HRESULT WINAPI ProxyEventSink_QueryInterface(IProxyProviderWinEventSink *iface, REFIID riid, void **obj) { *obj = NULL; @@ -1035,7 +1089,26 @@ static HRESULT WINAPI ProxyEventSink_AddAutomationPropertyChangedEvent(IProxyPro static HRESULT WINAPI ProxyEventSink_AddAutomationEvent(IProxyProviderWinEventSink *iface, IRawElementProviderSimple *elprov, EVENTID event_id) { - FIXME("%p, %p, %d: stub\n", iface, elprov, event_id); + const struct uia_event_info *event_info = uia_event_info_from_id(event_id); + struct event_sink_event *sink_event = calloc(1, sizeof(*sink_event)); + struct uia_event *event = impl_from_ProxyEventSink(iface); + + TRACE("%p, %p, %d\n", iface, elprov, event_id); + + if (!sink_event) + return E_OUTOFMEMORY; + + sink_event->args = create_uia_event_args(event_info); + if (!sink_event->args) + { + free(sink_event); + return E_OUTOFMEMORY; + } + + IRawElementProviderSimple_AddRef(elprov); + sink_event->elprov = elprov; + list_add_tail(event->u.clientside.sink_events, &sink_event->event_sink_list_entry); + return S_OK; }
@@ -1728,16 +1801,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; diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index de6e547dfa4..7a787d5efef 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -145,6 +145,8 @@ struct uia_event void *callback_data;
IProxyProviderWinEventSink IProxyProviderWinEventSink_iface; + struct list *sink_events; + struct rb_tree win_event_hwnd_map; BOOL event_thread_started; DWORD git_cookie;