uiautomationcore: Check if we should try to invoke IProxyProviderWinEventHandler::RespondToWinEvent for registered UIA events.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-09-14 13:05:31 -04:00 committed by Alexandre Julliard
parent b9cf4e9896
commit bc063b67ab
5 changed files with 65 additions and 16 deletions

View file

@ -16823,7 +16823,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para
SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); /* Only called twice on Win11. */
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[0], OBJID_WINDOW, CHILDID_SELF, event_handles,
1, FALSE, FALSE, FALSE);
todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
/*
* Get rid of our serverside provider and raise EVENT_OBJECT_FOCUS
@ -16848,7 +16848,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para
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, TRUE, 1, TRUE);
check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE);
method_sequences_enabled = FALSE;
/*
@ -16895,7 +16895,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,
1, TRUE, FALSE, TRUE);
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
/*
* Child HWND now has a serverside provider, WinEvent is ignored.
@ -16906,7 +16906,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 2); /* Only sent 2 times on Win11. */
test_uia_event_win_event_mapping(EVENT_OBJECT_FOCUS, hwnd[1], OBJID_WINDOW, CHILDID_SELF, event_handles,
1, FALSE, FALSE, FALSE);
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
CHECK_CALLED_AT_MOST(winproc_GETOBJECT_UiaRoot, 1);
/*
@ -16940,7 +16940,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, TRUE, 1, TRUE);
check_uia_hwnd_expects_at_least(1, TRUE, 1, TRUE, 1, TRUE, 1, FALSE, 1, TRUE);
/* Raise a WinEvent on our test child HWND, both event callbacks invoked. */
child_win_prov_root = NULL;
@ -16950,7 +16950,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para
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);
todo_wine CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2);
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);
/*
@ -16970,7 +16970,7 @@ static DWORD WINAPI uia_proxy_provider_win_event_handler_test_thread(LPVOID para
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);
todo_wine CHECK_CALLED_AT_LEAST(child_winproc_GETOBJECT_UiaRoot, 2);
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);
DestroyWindow(tmp_hwnd);

View file

@ -511,6 +511,44 @@ static HRESULT uia_raise_serverside_event(struct uia_queue_uia_event *event)
return hr;
}
/* Check the parent chain of HWNDs, excluding the desktop. */
static BOOL uia_win_event_hwnd_map_contains_ancestors(struct rb_tree *hwnd_map, HWND hwnd)
{
HWND parent = GetAncestor(hwnd, GA_PARENT);
const HWND desktop = GetDesktopWindow();
while (parent && (parent != desktop))
{
if (uia_hwnd_map_check_hwnd(hwnd_map, parent))
return TRUE;
parent = GetAncestor(parent, GA_PARENT);
}
return FALSE;
}
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;
/*
* Check if this HWND, or any of it's ancestors (excluding the desktop)
* are in our scope.
*/
if (!uia_hwnd_map_check_hwnd(&event->u.clientside.win_event_hwnd_map, win_event->hwnd) &&
!uia_win_event_hwnd_map_contains_ancestors(&event->u.clientside.win_event_hwnd_map, win_event->hwnd))
return S_OK;
/* Has a native serverside provider, no need to do WinEvent translation. */
if (UiaHasServerSideProvider(win_event->hwnd))
return S_OK;
FIXME("IProxyProviderWinEventHandler usage is currently unimplemented.\n");
return S_OK;
}
static void uia_event_thread_process_queue(struct list *event_queue)
{
while (1)
@ -538,6 +576,15 @@ static void uia_event_thread_process_queue(struct list *event_queue)
break;
}
case QUEUE_EVENT_TYPE_WIN_EVENT:
{
struct uia_queue_win_event *win_event = (struct uia_queue_win_event *)event;
hr = uia_event_for_each(win_event_to_uia_event_id(win_event->event_id), uia_win_event_for_each_callback,
(void *)win_event, TRUE);
break;
}
default:
break;
}

View file

@ -255,6 +255,8 @@ HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *el
HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;
int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN;
BOOL uia_hwnd_is_visible(HWND hwnd) DECLSPEC_HIDDEN;
BOOL uia_is_top_level_hwnd(HWND hwnd) DECLSPEC_HIDDEN;
BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd) DECLSPEC_HIDDEN;
HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd) DECLSPEC_HIDDEN;
void uia_hwnd_map_init(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN;
void uia_hwnd_map_destroy(struct rb_tree *hwnd_map) DECLSPEC_HIDDEN;

View file

@ -1545,11 +1545,6 @@ static HRESULT uia_send_message_timeout(HWND hwnd, UINT msg, WPARAM wparam, LPAR
return S_OK;
}
static BOOL is_top_level_hwnd(HWND hwnd)
{
return GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow();
}
static HRESULT get_uia_control_type_for_hwnd(HWND hwnd, int *control_type)
{
LONG_PTR style, ex_style;
@ -1576,7 +1571,7 @@ static HRESULT get_uia_control_type_for_hwnd(HWND hwnd, int *control_type)
}
/* Non top-level HWNDs are considered panes as well. */
if (!is_top_level_hwnd(hwnd))
if (!uia_is_top_level_hwnd(hwnd))
*control_type = UIA_PaneControlTypeId;
else
*control_type = UIA_WindowControlTypeId;
@ -1816,7 +1811,7 @@ static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *i
* Top level owned windows have their owner window as a parent instead
* of the desktop window.
*/
if (is_top_level_hwnd(base_hwnd_prov->hwnd) && (owner = GetWindow(base_hwnd_prov->hwnd, GW_OWNER)))
if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && (owner = GetWindow(base_hwnd_prov->hwnd, GW_OWNER)))
parent = owner;
else
parent = GetAncestor(base_hwnd_prov->hwnd, GA_PARENT);
@ -1866,7 +1861,7 @@ static HRESULT WINAPI base_hwnd_fragment_get_BoundingRectangle(IRawElementProvid
memset(ret_val, 0, sizeof(*ret_val));
/* Top level minimized window - Return empty rect. */
if (is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd))
if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd))
return S_OK;
if (!GetWindowRect(base_hwnd_prov->hwnd, &rect))

View file

@ -404,6 +404,11 @@ BOOL uia_hwnd_is_visible(HWND hwnd)
return TRUE;
}
BOOL uia_is_top_level_hwnd(HWND hwnd)
{
return GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow();
}
/*
* rbtree to efficiently store a collection of HWNDs.
*/
@ -429,7 +434,7 @@ static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
free(hwnd_entry);
}
static BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
{
return !!rb_get(hwnd_map, hwnd);
}