Module: wine Branch: master Commit: 01d9a5ea2b1d6ecf69a3b2ddd06e45a299a47212 URL: https://gitlab.winehq.org/wine/wine/-/commit/01d9a5ea2b1d6ecf69a3b2ddd06e45a...
Author: Connor McAdams cmcadams@codeweavers.com Date: Thu Sep 14 13:12:25 2023 -0400
uiautomationcore: Create HUIANODE for WinEvents that should invoke IProxyProviderWinEventHandler::RespondToWinEvent.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com
---
dlls/uiautomationcore/tests/uiautomation.c | 44 +++++++++++++-------- dlls/uiautomationcore/uia_event.c | 62 ++++++++++++++++++++++++++++++ 2 files changed, 91 insertions(+), 15 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 2685aba1b15..452587970d9 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1761,6 +1761,15 @@ 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. */ \ @@ -16708,11 +16717,17 @@ static const struct prov_method_sequence win_event_handler_seq[] = { { &Provider_hwnd2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+. */ { &Provider_nc2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_hwnd2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ - { &Provider_nc2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, - { &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT }, - NODE_CREATE_SEQ(&Provider_child), - { &Provider_child, FRAG_GET_RUNTIME_ID }, - { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ + /* + * The following two are currently only done on Wine. Windows doesn't do + * this because the node created is never passed out of the event thread. + */ + { &Provider_nc2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT, METHOD_TODO }, + { &Provider_hwnd2, WINEVENT_HANDLER_RESPOND_TO_WINEVENT, METHOD_TODO }, + NODE_CREATE_SEQ_TODO(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_TODO }, + { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
@@ -16846,9 +16861,8 @@ 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); - if (CALLED_COUNT(winproc_GETOBJECT_CLIENT)) - ok_method_sequence(win_event_handler_seq, "win_event_handler_seq"); - check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE); + 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;
/* @@ -16894,7 +16908,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para 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); - check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE); + check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE); CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
/* @@ -16940,7 +16954,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); - check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE); + 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. */ child_win_prov_root = NULL; @@ -16951,7 +16965,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles, ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); - check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 2, TRUE, 0, FALSE); + check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 2, TRUE, 0, FALSE);
/* * Raise a WinEvent on a descendant HWND of our test HWND. If any ancestor @@ -16971,7 +16985,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, tmp_hwnd2, OBJID_WINDOW, CHILDID_SELF, event_handles, ARRAY_SIZE(event_handles), TRUE, TRUE, TRUE); CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2); - check_uia_hwnd_expects_at_least(0, FALSE, 2, TRUE, 2, TRUE, 0, FALSE, 0, FALSE); + check_uia_hwnd_expects_at_least(0, FALSE, 2, FALSE, 2, FALSE, 0, FALSE, 0, FALSE);
DestroyWindow(tmp_hwnd); Provider_nc3.hwnd = Provider_hwnd3.hwnd = hwnd[1]; @@ -17018,7 +17032,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para 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); - check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 0, FALSE, 0, FALSE); + check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
/* * Top-level HWND, a child of the desktop HWND. Will not have an event @@ -17059,14 +17073,14 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para 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); - check_uia_hwnd_expects(1, TRUE, 1, TRUE, 1, TRUE, 2, TRUE, 1, TRUE); + 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); - check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE); + check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE);
hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 59f52cdcf3d..59b6d71c6c2 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -528,9 +528,57 @@ static BOOL uia_win_event_hwnd_map_contains_ancestors(struct rb_tree *hwnd_map, return FALSE; }
+static HRESULT create_msaa_provider_from_hwnd(HWND hwnd, int in_child_id, IRawElementProviderSimple **ret_elprov) +{ + IRawElementProviderSimple *elprov; + IAccessible *acc; + int child_id; + HRESULT hr; + + *ret_elprov = NULL; + hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc); + if (FAILED(hr)) + return hr; + + child_id = in_child_id; + if (in_child_id != CHILDID_SELF) + { + IDispatch *disp; + VARIANT cid; + + disp = NULL; + variant_init_i4(&cid, in_child_id); + hr = IAccessible_get_accChild(acc, cid, &disp); + if (FAILED(hr)) + TRACE("get_accChild failed with %#lx!\n", hr); + + if (SUCCEEDED(hr) && disp) + { + IAccessible_Release(acc); + hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)&acc); + IDispatch_Release(disp); + if (FAILED(hr)) + return hr; + + child_id = CHILDID_SELF; + } + } + + hr = create_msaa_provider(acc, child_id, hwnd, in_child_id == CHILDID_SELF, &elprov); + IAccessible_Release(acc); + if (FAILED(hr)) + return hr; + + *ret_elprov = elprov; + return S_OK; +} + 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; + IRawElementProviderSimple *elprov; + HUIANODE node; + HRESULT hr;
/* * Check if this HWND, or any of it's ancestors (excluding the desktop) @@ -544,8 +592,22 @@ static HRESULT uia_win_event_for_each_callback(struct uia_event *event, void *da if (UiaHasServerSideProvider(win_event->hwnd)) return S_OK;
+ /* + * Regardless of the object ID of the WinEvent, OBJID_CLIENT is queried + * for the HWND with the same child ID as the WinEvent. + */ + hr = create_msaa_provider_from_hwnd(win_event->hwnd, win_event->child_id, &elprov); + if (FAILED(hr)) + return hr; + + hr = create_uia_node_from_elprov(elprov, &node, TRUE); + IRawElementProviderSimple_Release(elprov); + if (FAILED(hr)) + return hr; + FIXME("IProxyProviderWinEventHandler usage is currently unimplemented.\n");
+ UiaNodeRelease(node); return S_OK; }