uiautomationcore: Use EVENT_OBJECT_SHOW to advise providers of events being listened for in the COM API.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-09-15 12:49:30 -04:00 committed by Alexandre Julliard
parent c21bc70af8
commit 3f4f116dc5
4 changed files with 107 additions and 29 deletions

View file

@ -14943,8 +14943,8 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
set_provider_method_event_data(&Provider, NULL, -1);
goto exit;
}
todo_wine ok(wait_res != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
ok(wait_res != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
/*
* Manually fire off EVENT_OBJECT_SHOW, providers will be advised of
@ -14952,8 +14952,8 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
*/
set_uia_hwnd_expects(0, 2, 2, 6, 0); /* Only done more than one of each on Win11. */
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_WINDOW, CHILDID_SELF);
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
/*
* Providers are only advised of events being listened for if an event is
@ -14977,17 +14977,17 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 6); /* Only done more than once on Win11. */
set_uia_hwnd_expects(0, 2, 3, 5, 0); /* Only done more than one of each on Win11. */
ShowWindow(test_child_hwnd, SW_SHOW);
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
/* Same deal as before, it will advise multiple times. */
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 6); /* Only done more than once on Win11. */
set_uia_hwnd_expects(0, 2, 3, 5, 0); /* Only done more than one of each on Win11. */
NotifyWinEvent(EVENT_OBJECT_SHOW, test_child_hwnd, OBJID_WINDOW, CHILDID_SELF);
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
ok(msg_wait_for_all_events(method_event, event_handle_count, 3000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 1, FALSE, 0, FALSE);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
/* Break navigation chain, can't reach our test element so no advisement. */
Provider_hwnd3.parent = NULL;
@ -14995,8 +14995,8 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
set_uia_hwnd_expects(0, 1, 1, 1, 0);
NotifyWinEvent(EVENT_OBJECT_SHOW, test_child_hwnd, OBJID_WINDOW, CHILDID_SELF);
ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) == WAIT_TIMEOUT, "Wait for method_event(s) didn't timeout.\n");
check_uia_hwnd_expects(0, FALSE, 1, TRUE, 1, TRUE, 1, TRUE, 0, FALSE);
todo_wine CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
check_uia_hwnd_expects(0, FALSE, 1, FALSE, 1, FALSE, 1, TRUE, 0, FALSE);
CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot);
set_provider_method_event_data(&Provider_hwnd3, NULL, -1);
set_provider_method_event_data(&Provider_nc3, NULL, -1);
@ -15044,10 +15044,10 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); /* Only done on Win11. */
set_uia_hwnd_expects(0, 3, 3, 1, 0); /* Only done more than once on Win11. */
NotifyWinEvent(EVENT_OBJECT_SHOW, GetDesktopWindow(), OBJID_WINDOW, CHILDID_SELF);
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
CHECK_CALLED_AT_MOST(winproc_GETOBJECT_UiaRoot, 1);
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 1);
check_uia_hwnd_expects_at_least(0, FALSE, 1, TRUE, 1, TRUE, 0, FALSE, 0, FALSE);
check_uia_hwnd_expects_at_least(0, FALSE, 1, FALSE, 1, FALSE, 0, FALSE, 0, FALSE);
set_provider_method_event_data(&Provider_hwnd, NULL, -1);
set_provider_method_event_data(&Provider_nc, NULL, -1);
@ -15063,7 +15063,7 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); /* Only done on Win11. */
set_uia_hwnd_expects(0, 2, 2, 7, 0); /* Only done more than once on Win11. */
NotifyWinEvent(EVENT_OBJECT_SHOW, test_hwnd, OBJID_WINDOW, CHILDID_SELF);
todo_wine ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
ok(msg_wait_for_all_events(method_event, event_handle_count, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 1);
check_uia_hwnd_expects_at_most(0, 2, 2, 7, 0);

View file

@ -960,7 +960,77 @@ struct uia_com_event {
HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG child_id, DWORD thread_id, DWORD event_time)
{
FIXME("%ld, %p, %ld, %ld, %ld, %ld: stub\n", event_id, hwnd, obj_id, child_id, thread_id, event_time);
LONG handler_count;
TRACE("%ld, %p, %ld, %ld, %ld, %ld\n", event_id, hwnd, obj_id, child_id, thread_id, event_time);
EnterCriticalSection(&com_event_handlers_cs);
handler_count = com_event_handlers.handler_count;
LeaveCriticalSection(&com_event_handlers_cs);
if (!handler_count)
return S_OK;
switch (event_id)
{
case EVENT_OBJECT_SHOW:
{
struct uia_event_handler_map_entry *entry;
SAFEARRAY *rt_id = NULL;
HUIANODE node;
HRESULT hr;
if (obj_id != OBJID_WINDOW || !uia_hwnd_is_visible(hwnd))
break;
hr = UiaNodeFromHandle(hwnd, &node);
if (FAILED(hr))
return hr;
hr = UiaGetRuntimeId(node, &rt_id);
if (FAILED(hr))
{
UiaNodeRelease(node);
return hr;
}
EnterCriticalSection(&com_event_handlers_cs);
RB_FOR_EACH_ENTRY(entry, &com_event_handlers.handler_map, struct uia_event_handler_map_entry, entry)
{
struct uia_com_event *event;
/*
* Focus change event handlers only listen for EVENT_OBJECT_SHOW
* on the desktop HWND.
*/
if ((entry->event_id == UIA_AutomationFocusChangedEventId) && (hwnd != GetDesktopWindow()))
continue;
LIST_FOR_EACH_ENTRY(event, &entry->handlers_list, struct uia_com_event, event_handler_map_list_entry)
{
hr = uia_event_check_node_within_event_scope((struct uia_event *)event->event, node, rt_id, NULL);
if (FAILED(hr))
WARN("uia_event_check_node_within_scope failed with hr %#lx\n", hr);
else if (hr == S_OK)
{
hr = uia_event_advise_node((struct uia_event *)event->event, node);
if (FAILED(hr))
WARN("uia_event_advise_node failed with hr %#lx\n", hr);
}
}
}
LeaveCriticalSection(&com_event_handlers_cs);
UiaNodeRelease(node);
break;
}
default:
break;
}
return S_OK;
}

View file

@ -55,6 +55,7 @@ static int win_event_to_uia_event_id(int win_event)
{
case EVENT_OBJECT_FOCUS: return UIA_AutomationFocusChangedEventId;
case EVENT_SYSTEM_ALERT: return UIA_SystemAlertEventId;
case EVENT_OBJECT_SHOW: return UIA_StructureChangedEventId;
default:
break;
@ -1579,13 +1580,27 @@ static HRESULT uia_event_advise(struct uia_event *event, BOOL advise_added, LONG
return hr;
}
HRESULT uia_event_advise_node(struct uia_event *event, HUIANODE node)
{
int old_event_advisers_count = event->event_advisers_count;
HRESULT hr;
hr = attach_event_to_uia_node(node, event);
if (FAILED(hr))
return hr;
if (event->event_advisers_count != old_event_advisers_count)
hr = uia_event_advise(event, TRUE, old_event_advisers_count);
return hr;
}
/***********************************************************************
* UiaEventAddWindow (uiautomationcore.@)
*/
HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd)
{
struct uia_event *event = unsafe_impl_from_IWineUiaEvent((IWineUiaEvent *)huiaevent);
int old_event_advisers_count;
HUIANODE node;
HRESULT hr;
@ -1600,15 +1615,7 @@ HRESULT WINAPI UiaEventAddWindow(HUIAEVENT huiaevent, HWND hwnd)
if (FAILED(hr))
return hr;
old_event_advisers_count = event->event_advisers_count;
hr = attach_event_to_uia_node(node, event);
if (FAILED(hr))
goto exit;
if (event->event_advisers_count != old_event_advisers_count)
hr = uia_event_advise(event, TRUE, old_event_advisers_count);
exit:
hr = uia_event_advise_node(event, node);
UiaNodeRelease(node);
return hr;
@ -1734,8 +1741,6 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent)
return S_OK;
}
static HRESULT uia_event_check_node_within_event_scope(struct uia_event *event, HUIANODE node, SAFEARRAY *rt_id,
HUIANODE *clientside_nav_node_out);
static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args, struct uia_event *event)
{
HRESULT hr = S_OK;
@ -1812,7 +1817,7 @@ static void set_refuse_hwnd_providers(struct uia_node *node, BOOL refuse_hwnd_pr
* If it isn't, return S_FALSE.
* Upon failure, return a failure HR.
*/
static HRESULT uia_event_check_node_within_event_scope(struct uia_event *event, HUIANODE node, SAFEARRAY *rt_id,
HRESULT uia_event_check_node_within_event_scope(struct uia_event *event, HUIANODE node, SAFEARRAY *rt_id,
HUIANODE *clientside_nav_node_out)
{
struct UiaPropertyCondition prop_cond = { ConditionType_Property, UIA_RuntimeIdPropertyId };

View file

@ -234,9 +234,12 @@ HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_i
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events,
struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, struct uia_event *event) DECLSPEC_HIDDEN;
HRESULT uia_event_advise_node(struct uia_event *event, HUIANODE node) DECLSPEC_HIDDEN;
HRESULT uia_add_clientside_event(HUIANODE huianode, EVENTID event_id, enum TreeScope scope, PROPERTYID *prop_ids,
int prop_ids_count, struct UiaCacheRequest *cache_req, SAFEARRAY *rt_id, UiaWineEventCallback *cback,
void *cback_data, HUIAEVENT *huiaevent) DECLSPEC_HIDDEN;
HRESULT uia_event_check_node_within_event_scope(struct uia_event *event, HUIANODE node, SAFEARRAY *rt_id,
HUIANODE *clientside_nav_node_out) DECLSPEC_HIDDEN;
/* uia_ids.c */
const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN;