From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 43 ++++++++++++++++++++++ dlls/uiautomationcore/uia_client.c | 18 --------- dlls/uiautomationcore/uia_event.c | 37 +++++++++++++++++++ dlls/uiautomationcore/uia_private.h | 2 + dlls/uiautomationcore/uia_utils.c | 17 +++++++++ 5 files changed, 99 insertions(+), 18 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 0ad9a883c1c..efcba1c2b5f 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -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); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index a94a6b8db81..e1dd7d0bd23 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -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; diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index e1061003d56..7e757d9dee0 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -23,6 +23,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. */ @@ -74,6 +100,11 @@ 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) { struct uia_event_map_entry *event_entry = uia_get_event_map_entry_for_event(event->event_id); + const int subtree_scope = TreeScope_Element | TreeScope_Descendants; + + 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) @@ -489,6 +520,12 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct Uia return S_OK;
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); + if (event->desktop_subtree_event) + { + hr = uia_event_invoke(node, args, event); + goto exit; + } + if (rt_id && !uia_compare_safearrays(rt_id, event->runtime_id, UIAutomationType_IntArray)) { if (event->scope & TreeScope_Element) diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index dcdaaa69f1b..9fd80dba7da 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -98,6 +98,7 @@ struct uia_event IWineUiaEvent IWineUiaEvent_iface; LONG ref;
+ BOOL desktop_subtree_event; SAFEARRAY *runtime_id; int event_id; int scope; @@ -189,6 +190,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; diff --git a/dlls/uiautomationcore/uia_utils.c b/dlls/uiautomationcore/uia_utils.c index 03fdef40e01..8e034916397 100644 --- a/dlls/uiautomationcore/uia_utils.c +++ b/dlls/uiautomationcore/uia_utils.c @@ -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. */