uiautomationcore: Unconditionally match all events registered on the desktop node with a scope of subtree.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-05-18 11:31:00 -04:00 committed by Alexandre Julliard
parent c5b2c0369b
commit c7431990d8
5 changed files with 96 additions and 18 deletions

View file

@ -14237,6 +14237,49 @@ static void test_UiaAddEvent(void)
todo_wine CHECK_CALLED_MULTI(prov_callback_proxy, 2);
CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
/*
* Register an event on the desktop HWND with a scope of TreeScope_Element
* and TreeScope_Descendants. This is a special case where all providers
* will match, regardless of whether or not they can navigate to the
* desktop node.
*/
set_cache_request(&cache_req, (struct UiaCondition *)&UiaTrueCondition, TreeScope_Element, NULL, 0, NULL, 0,
AutomationElementMode_Full);
hr = UiaAddEvent(node, UIA_AutomationFocusChangedEventId, uia_event_callback, TreeScope_Element | TreeScope_Descendants, NULL, 0,
&cache_req, &event);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!event, "event == NULL\n");
/*
* Raise an event on Provider2 - completely disconnected from all other
* providers, will still trigger the event callback.
*/
initialize_provider(&Provider2, ProviderOptions_ServerSideProvider, NULL, TRUE);
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
add_provider_desc(&exp_node_desc, L"Main", L"Provider2", TRUE);
set_event_data(0, 0, 1, 1, &exp_node_desc, L"P)");
SET_EXPECT(uia_event_callback);
hr = UiaRaiseAutomationEvent(&Provider2.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(uia_event_callback);
/*
* No clientside providers to match us to the desktop node through
* navigation, but event will still be triggered.
*/
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), hwnd);
add_provider_desc(&exp_node_desc, L"Main", L"Provider_hwnd2", TRUE);
set_event_data(0, 0, 1, 1, &exp_node_desc, L"P)");
SET_EXPECT(uia_event_callback);
Provider_hwnd2.prov_opts = ProviderOptions_ServerSideProvider;
Provider_hwnd2.ignore_hwnd_prop = TRUE;
hr = UiaRaiseAutomationEvent(&Provider_hwnd2.IRawElementProviderSimple_iface, UIA_AutomationFocusChangedEventId);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
UiaNodeRelease(node);

View file

@ -2692,30 +2692,12 @@ HRESULT WINAPI UiaGetPropertyValue(HUIANODE huianode, PROPERTYID prop_id, VARIAN
return hr;
}
#define UIA_RUNTIME_ID_PREFIX 42
enum fragment_root_prov_type_ids {
FRAGMENT_ROOT_NONCLIENT_TYPE_ID = 0x03,
FRAGMENT_ROOT_MAIN_TYPE_ID = 0x04,
FRAGMENT_ROOT_OVERRIDE_TYPE_ID = 0x05,
};
static HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd)
{
const int rt_id[2] = { UIA_RUNTIME_ID_PREFIX, HandleToUlong(hwnd) };
HRESULT hr;
LONG idx;
for (idx = 0; idx < ARRAY_SIZE(rt_id); idx++)
{
hr = SafeArrayPutElement(sa, &idx, (void *)&rt_id[idx]);
if (FAILED(hr))
return hr;
}
return S_OK;
}
static SAFEARRAY *append_uia_runtime_id(SAFEARRAY *sa, HWND hwnd, enum ProviderOptions root_opts)
{
LONG i, idx, lbound, elems;

View file

@ -24,6 +24,32 @@
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
static SAFEARRAY *uia_desktop_node_rt_id;
static BOOL WINAPI uia_init_desktop_rt_id(INIT_ONCE *once, void *param, void **ctx)
{
SAFEARRAY *sa;
if ((sa = SafeArrayCreateVector(VT_I4, 0, 2)))
{
if (SUCCEEDED(write_runtime_id_base(sa, GetDesktopWindow())))
uia_desktop_node_rt_id = sa;
else
SafeArrayDestroy(sa);
}
return !!uia_desktop_node_rt_id;
}
static SAFEARRAY *uia_get_desktop_rt_id(void)
{
static INIT_ONCE once = INIT_ONCE_STATIC_INIT;
if (!uia_desktop_node_rt_id)
InitOnceExecuteOnce(&once, uia_init_desktop_rt_id, NULL, NULL);
return uia_desktop_node_rt_id;
}
/*
* UI Automation event map.
*/
@ -81,8 +107,13 @@ static struct uia_event_map_entry *uia_get_event_map_entry_for_event(int event_i
static HRESULT uia_event_map_add_event(struct uia_event *event)
{
const int subtree_scope = TreeScope_Element | TreeScope_Descendants;
struct uia_event_map_entry *event_entry;
if (((event->scope & subtree_scope) == subtree_scope) && event->runtime_id &&
!uia_compare_safearrays(uia_get_desktop_rt_id(), event->runtime_id, UIAutomationType_IntArray))
event->desktop_subtree_event = TRUE;
EnterCriticalSection(&event_map_cs);
if (!(event_entry = uia_get_event_map_entry_for_event(event->event_id)))
@ -539,6 +570,9 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct Uia
if (!event->runtime_id)
return S_OK;
if (event->desktop_subtree_event)
return uia_event_invoke(node, args, event);
if (rt_id && !uia_compare_safearrays(rt_id, event->runtime_id, UIAutomationType_IntArray))
{
if (event->scope & TreeScope_Element)

View file

@ -98,6 +98,7 @@ struct uia_event
IWineUiaEvent IWineUiaEvent_iface;
LONG ref;
BOOL desktop_subtree_event;
SAFEARRAY *runtime_id;
int event_id;
int scope;
@ -190,6 +191,7 @@ HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL kn
HRESULT register_interface_in_git(IUnknown *iface, REFIID riid, DWORD *ret_cookie) DECLSPEC_HIDDEN;
HRESULT unregister_interface_in_git(DWORD git_cookie) DECLSPEC_HIDDEN;
HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface) DECLSPEC_HIDDEN;
HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd) DECLSPEC_HIDDEN;
void uia_cache_request_destroy(struct UiaCacheRequest *cache_req) DECLSPEC_HIDDEN;
HRESULT uia_cache_request_clone(struct UiaCacheRequest *dst, struct UiaCacheRequest *src) DECLSPEC_HIDDEN;
HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN;

View file

@ -98,6 +98,23 @@ HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface
return S_OK;
}
#define UIA_RUNTIME_ID_PREFIX 42
HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd)
{
const int rt_id[2] = { UIA_RUNTIME_ID_PREFIX, HandleToUlong(hwnd) };
HRESULT hr;
LONG idx;
for (idx = 0; idx < ARRAY_SIZE(rt_id); idx++)
{
hr = SafeArrayPutElement(sa, &idx, (void *)&rt_id[idx]);
if (FAILED(hr))
return hr;
}
return S_OK;
}
/*
* UiaCondition cloning functions.
*/