Commit 4569157b authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Use EVENT_OBJECT_DESTROY to remove HWNDs from the COM API focus change HWND map.

parent a275834b
......@@ -15475,6 +15475,30 @@ static void test_uia_com_event_handler_event_advisement(IUIAutomation *uia_iface
check_uia_hwnd_expects_at_most(0, 1, 1, 3, 0);
test_hwnd_providers_event_advise_added(&Provider, &Provider_hwnd2, &Provider_nc2, 0, FALSE);
/* HWND destruction is tracked with EVENT_OBJECT_DESTROY/OBJID_WINDOW. */
NotifyWinEvent(EVENT_OBJECT_DESTROY, test_child_hwnd, OBJID_WINDOW, CHILDID_SELF);
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
/*
* EVENT_OBJECT_DESTROY removed this HWND, EVENT_OBJECT_FOCUS will now
* advise it again.
*/
reset_event_advise_values_for_hwnd_providers(&Provider2, &Provider_hwnd3, &Provider_nc3);
set_provider_method_event_data(&Provider2, method_event[0], ADVISE_EVENTS_EVENT_ADDED);
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, 3); /* Only sent 3 times on Win11. */
set_uia_hwnd_expects(0, 1, 1, 2, 0); /* Only Win11 sends WM_GETOBJECT 2 times. */
NotifyWinEvent(EVENT_OBJECT_FOCUS, test_child_hwnd, OBJID_CLIENT, CHILDID_SELF);
ok(msg_wait_for_all_events(method_event, 1, 2000) != WAIT_TIMEOUT, "Wait for method_event(s) timed out.\n");
if (wait_for_clientside_callbacks(2000)) trace("Kept getting callbacks up until timeout\n");
set_provider_method_event_data(&Provider2, NULL, -1);
check_uia_hwnd_expects_at_most(0, 1, 1, 2, 0);
CHECK_CALLED_AT_MOST(child_winproc_GETOBJECT_UiaRoot, 3);
test_provider_event_advise_added(&Provider2, UIA_AutomationFocusChangedEventId, FALSE);
test_provider_event_advise_added(&Provider_hwnd3, 0, FALSE);
test_provider_event_advise_added(&Provider_nc3, 0, FALSE);
set_uia_hwnd_expects(0, 1, 1, 0, 0);
hr = IUIAutomation_RemoveFocusChangedEventHandler(uia_iface,
&FocusChangedHandler.IUIAutomationFocusChangedEventHandler_iface);
......
......@@ -1108,6 +1108,38 @@ HRESULT uia_com_win_event_callback(DWORD event_id, HWND hwnd, LONG obj_id, LONG
break;
}
case EVENT_OBJECT_DESTROY:
{
static const int uia_event_id = UIA_AutomationFocusChangedEventId;
struct rb_entry *rb_entry;
if (obj_id != OBJID_WINDOW)
break;
EnterCriticalSection(&com_event_handlers_cs);
if ((rb_entry = rb_get(&com_event_handlers.handler_event_id_map, &uia_event_id)))
{
struct uia_event_handler_event_id_map_entry *event_id_map;
struct uia_event_handler_map_entry *entry;
event_id_map = RB_ENTRY_VALUE(rb_entry, struct uia_event_handler_event_id_map_entry, entry);
LIST_FOR_EACH_ENTRY(entry, &event_id_map->handlers_list, struct uia_event_handler_map_entry,
handler_event_id_map_list_entry)
{
struct uia_com_event *event;
LIST_FOR_EACH_ENTRY(event, &entry->handlers_list, struct uia_com_event, event_handler_map_list_entry)
{
uia_hwnd_map_remove_hwnd(&event->focus_hwnd_map, hwnd);
}
}
}
LeaveCriticalSection(&com_event_handlers_cs);
break;
}
default:
break;
}
......
......@@ -56,6 +56,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;
case EVENT_OBJECT_DESTROY: return UIA_StructureChangedEventId;
default:
break;
......
......@@ -270,5 +270,6 @@ 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_remove_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;
......@@ -459,6 +459,23 @@ HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
return S_OK;
}
void uia_hwnd_map_remove_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
{
struct rb_entry *rb_entry = rb_get(hwnd_map, hwnd);
struct uia_hwnd_map_entry *entry;
if (!rb_entry)
{
TRACE("hwnd %p not in map %p, nothing to remove.\n", hwnd, hwnd_map);
return;
}
TRACE("Removing hwnd %p from map %p\n", hwnd, hwnd_map);
entry = RB_ENTRY_VALUE(rb_entry, struct uia_hwnd_map_entry, entry);
rb_remove(hwnd_map, &entry->entry);
free(entry);
}
void uia_hwnd_map_init(struct rb_tree *hwnd_map)
{
rb_init(hwnd_map, uia_hwnd_map_hwnd_compare);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment