From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_client.c | 14 ++++++++------ dlls/uiautomationcore/uia_private.h | 1 + dlls/uiautomationcore/uia_provider.c | 2 +- 3 files changed, 10 insertions(+), 7 deletions(-)
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 8dac22db066..d9a13647246 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -1334,13 +1334,14 @@ static ULONG WINAPI uia_provider_Release(IWineUiaProvider *iface) }
static HRESULT get_variant_for_elprov_node(IRawElementProviderSimple *elprov, BOOL out_nested, - VARIANT *v) + BOOL refuse_hwnd_providers, VARIANT *v) { HUIANODE node; HRESULT hr;
VariantInit(v); - hr = create_uia_node_from_elprov(elprov, &node, !out_nested); + + hr = create_uia_node_from_elprov(elprov, &node, !refuse_hwnd_providers); IRawElementProviderSimple_Release(elprov); if (SUCCEEDED(hr)) { @@ -1444,7 +1445,7 @@ static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, if (FAILED(hr)) goto exit;
- hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, ret_val); + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, prov->refuse_hwnd_node_providers, ret_val); if (FAILED(hr)) return hr;
@@ -1770,7 +1771,7 @@ static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir if (FAILED(hr) || !elprov) return hr;
- hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, out_val); + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, prov->refuse_hwnd_node_providers, out_val); if (FAILED(hr)) return hr; } @@ -1802,7 +1803,7 @@ static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, VARIANT *o IRawElementProviderFragment_Release(elfrag); if (SUCCEEDED(hr)) { - hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, out_val); + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, prov->refuse_hwnd_node_providers, out_val); if (FAILED(hr)) VariantClear(out_val); } @@ -1881,7 +1882,7 @@ static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PT if (FAILED(hr)) goto exit;
- hr = create_uia_node_from_elprov(elprov, &node, !prov->return_nested_node); + hr = create_uia_node_from_elprov(elprov, &node, !prov->refuse_hwnd_node_providers); IRawElementProviderSimple_Release(elprov); if (SUCCEEDED(hr)) { @@ -2437,6 +2438,7 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU
IWineUiaProvider_AddRef(provider_iface); prov_data = impl_from_IWineUiaProvider(provider_iface); + prov_data->refuse_hwnd_node_providers = FALSE; prov_data->return_nested_node = FALSE; prov_data->parent_check_ran = FALSE;
diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 807ca134521..11cab86651c 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -84,6 +84,7 @@ struct uia_provider { LONG ref;
IRawElementProviderSimple *elprov; + BOOL refuse_hwnd_node_providers; BOOL return_nested_node; BOOL parent_check_ran; BOOL has_parent; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 38ddcd8678f..f13b028cad6 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1751,7 +1751,7 @@ static HRESULT uia_provider_thread_add_node(HUIANODE node, SAFEARRAY *rt_id) HRESULT hr = S_OK;
prov_data = impl_from_IWineUiaProvider(node_data->prov[prov_type]); - node_data->nested_node = prov_data->return_nested_node = TRUE; + node_data->nested_node = prov_data->return_nested_node = prov_data->refuse_hwnd_node_providers = TRUE;
TRACE("Adding node %p\n", node);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 10 +- dlls/uiautomationcore/uia_classes.idl | 2 +- dlls/uiautomationcore/uia_event.c | 153 +++++++++++++++------ 3 files changed, 117 insertions(+), 48 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 242f800d5db..a1ca9e62697 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -14063,11 +14063,11 @@ static void test_UiaAddEvent_client_proc(void) SET_EXPECT(uia_event_callback);
post_event_message(hwnd, WM_UIA_TEST_RAISE_EVENT, 0, PROVIDER_CHILD_ID, ProviderOptions_ServerSideProvider); - todo_wine ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); - todo_wine CHECK_CALLED_MULTI(prov_callback_nonclient, 2); + ok(!WaitForSingleObject(EventData.event_handle, 2000), "Wait for event_handle failed.\n"); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED_MULTI(prov_callback_nonclient, 2); todo_wine CHECK_CALLED_MULTI(prov_callback_proxy, 2); - todo_wine CHECK_CALLED(uia_event_callback); + CHECK_CALLED(uia_event_callback);
hr = UiaRemoveEvent(event); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -14696,7 +14696,7 @@ static void test_UiaAddEvent(const char *name) } }
- todo_wine CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_UiaRoot, 5); + CHECK_CALLED_AT_LEAST(winproc_GETOBJECT_UiaRoot, 5); GetExitCodeProcess(proc.hProcess, &exit_code); if (exit_code > 255) ok(0, "unhandled exception %08x in child process %04x\n", (UINT)exit_code, (UINT)GetProcessId(proc.hProcess)); diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 8eb9998f945..b1dea2d414d 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -75,7 +75,7 @@ library UIA_wine_private HRESULT advise_events([in]BOOL advise_added, [in]long adviser_start_idx); HRESULT set_event_data([in]const GUID *event_guid, [in]long scope, [in]VARIANT runtime_id, [in]IWineUiaEvent *event_iface); - HRESULT raise_event([in]VARIANT in_node); + HRESULT raise_event([in]VARIANT in_node, [in]VARIANT in_nav_start_node); }
[ diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c index 563c16066db..801ccf4a705 100644 --- a/dlls/uiautomationcore/uia_event.c +++ b/dlls/uiautomationcore/uia_event.c @@ -282,9 +282,11 @@ struct uia_queue_event union { struct { HUIANODE node; + HUIANODE nav_start_node; } serverside; struct { LRESULT node; + LRESULT nav_start_node; } clientside; } u; }; @@ -316,52 +318,82 @@ static struct uia_queue_event *uia_event_queue_pop(struct list *event_queue) return queue_event; }
-static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, struct uia_event *event); +static void uia_node_lresult_release(LRESULT lr) +{ + IWineUiaNode *node; + + if (lr && SUCCEEDED(ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&node))) + IWineUiaNode_Release(node); +} + +static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args, + struct uia_event *event); static HRESULT uia_raise_clientside_event(struct uia_queue_event *event) { - HUIANODE node; + HUIANODE node, nav_start_node; HRESULT hr;
+ node = nav_start_node = NULL; hr = uia_node_from_lresult(event->u.clientside.node, &node); - if (SUCCEEDED(hr)) + if (FAILED(hr)) { - hr = uia_event_invoke(node, event->args, event->event); - UiaNodeRelease(node); + WARN("Failed to create node from lresult, hr %#lx\n", hr); + uia_node_lresult_release(event->u.clientside.nav_start_node); + return hr; + } + + if (event->u.clientside.nav_start_node) + { + hr = uia_node_from_lresult(event->u.clientside.nav_start_node, &nav_start_node); + if (FAILED(hr)) + { + WARN("Failed to create nav_start_node from lresult, hr %#lx\n", hr); + UiaNodeRelease(node); + return hr; + } }
+ hr = uia_event_invoke(node, nav_start_node, event->args, event->event); + UiaNodeRelease(node); + UiaNodeRelease(nav_start_node); + return hr; }
static HRESULT uia_raise_serverside_event(struct uia_queue_event *event) { HRESULT hr = S_OK; - LRESULT lr; + LRESULT lr, lr2; + VARIANT v, v2;
/* * uia_lresult_from_node is expected to release the node here upon * failure. */ - if ((lr = uia_lresult_from_node(event->u.serverside.node))) + lr = lr2 = 0; + if (!(lr = uia_lresult_from_node(event->u.serverside.node))) { - VARIANT v; + UiaNodeRelease(event->u.serverside.nav_start_node); + return E_FAIL; + }
- V_VT(&v) = VT_I4; - V_I4(&v) = lr; - hr = IWineUiaEvent_raise_event(event->event->u.serverside.event_iface, v); - if (FAILED(hr)) - { - IWineUiaNode *node; - - /* - * If the method returned failure, make sure we don't leave a - * dangling IWineUiaNode. - */ - if (SUCCEEDED(ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&node))) - IWineUiaNode_Release(node); - } + if (event->u.serverside.nav_start_node && !(lr2 = uia_lresult_from_node(event->u.serverside.nav_start_node))) + { + uia_node_lresult_release(lr); + return E_FAIL; + } + + VariantInit(&v2); + variant_init_i4(&v, lr); + if (lr2) + variant_init_i4(&v2, lr2); + + hr = IWineUiaEvent_raise_event(event->event->u.serverside.event_iface, v, v2); + if (FAILED(hr)) + { + uia_node_lresult_release(lr); + uia_node_lresult_release(lr2); } - else - hr = E_FAIL;
return hr; } @@ -635,13 +667,13 @@ static HRESULT WINAPI uia_event_set_event_data(IWineUiaEvent *iface, const GUID return S_OK; }
-static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node) +static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_node, VARIANT in_nav_start_node) { struct uia_event *event = impl_from_IWineUiaEvent(iface); struct uia_queue_event *queue_event; struct uia_event_args *args;
- TRACE("%p, %s\n", iface, debugstr_variant(&in_node)); + TRACE("%p, %s, %s\n", iface, debugstr_variant(&in_node), debugstr_variant(&in_nav_start_node));
assert(event->event_type != EVENT_TYPE_SERVERSIDE);
@@ -658,6 +690,8 @@ static HRESULT WINAPI uia_event_raise_event(IWineUiaEvent *iface, VARIANT in_nod queue_event->args = args; queue_event->event = event; queue_event->u.clientside.node = V_I4(&in_node); + if (V_VT(&in_nav_start_node) == VT_I4) + queue_event->u.clientside.nav_start_node = V_I4(&in_nav_start_node);
IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); uia_event_queue_push(queue_event); @@ -1193,7 +1227,9 @@ HRESULT WINAPI UiaRemoveEvent(HUIAEVENT huiaevent) return S_OK; }
-static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, struct uia_event *event) +static HRESULT uia_event_check_match(HUIANODE node, HUIANODE nav_start_node, SAFEARRAY *rt_id, + struct uia_event_args *args, struct uia_event *event); +static HRESULT uia_event_invoke(HUIANODE node, HUIANODE nav_start_node, struct uia_event_args *args, struct uia_event *event) { HRESULT hr = S_OK;
@@ -1202,6 +1238,9 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru SAFEARRAY *out_req; BSTR tree_struct;
+ if (nav_start_node) + return uia_event_check_match(node, nav_start_node, NULL, args, event); + hr = UiaGetUpdatedCache(node, &event->u.clientside.cache_req, NormalizeState_View, NULL, &out_req, &tree_struct); if (SUCCEEDED(hr)) @@ -1214,11 +1253,12 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru else { struct uia_queue_event *queue_event; - HUIANODE node2; + HUIANODE node2, nav_start_node2;
if (!(queue_event = heap_alloc_zero(sizeof(*queue_event)))) return E_OUTOFMEMORY;
+ node2 = nav_start_node2 = NULL; hr = clone_uia_node(node, &node2); if (FAILED(hr)) { @@ -1226,10 +1266,22 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru return hr; }
+ if (nav_start_node) + { + hr = clone_uia_node(nav_start_node, &nav_start_node2); + if (FAILED(hr)) + { + heap_free(queue_event); + UiaNodeRelease(node2); + return hr; + } + } + queue_event->queue_event_type = QUEUE_EVENT_TYPE_SERVERSIDE; queue_event->args = args; queue_event->event = event; queue_event->u.serverside.node = node2; + queue_event->u.serverside.nav_start_node = nav_start_node2;
InterlockedIncrement(&args->ref); IWineUiaEvent_AddRef(&event->IWineUiaEvent_iface); @@ -1239,14 +1291,21 @@ static HRESULT uia_event_invoke(HUIANODE node, struct uia_event_args *args, stru return hr; }
+static void set_refuse_hwnd_providers(struct uia_node *node, BOOL refuse_hwnd_providers) +{ + struct uia_provider *prov_data = impl_from_IWineUiaProvider(node->prov[get_node_provider_type_at_idx(node, 0)]); + + prov_data->refuse_hwnd_node_providers = refuse_hwnd_providers; +} + /* * Check if the provider that raised the event matches this particular event. */ -static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia_event_args *args, - struct uia_event *event) +static HRESULT uia_event_check_match(HUIANODE node, HUIANODE nav_start_node, SAFEARRAY *rt_id, + struct uia_event_args *args, struct uia_event *event) { struct UiaPropertyCondition prop_cond = { ConditionType_Property, UIA_RuntimeIdPropertyId }; - struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node); + struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)nav_start_node); HRESULT hr = S_OK;
/* Event is no longer valid. */ @@ -1258,24 +1317,18 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia return S_OK;
if (event->desktop_subtree_event) - return uia_event_invoke(node, args, event); + return uia_event_invoke(node, NULL, args, event);
if (rt_id && !uia_compare_safearrays(rt_id, event->runtime_id, UIAutomationType_IntArray)) { if (event->scope & TreeScope_Element) - hr = uia_event_invoke(node, args, event); + hr = uia_event_invoke(node, NULL, args, event); return hr; }
if (!(event->scope & (TreeScope_Descendants | TreeScope_Children))) return S_OK;
- if (event->event_type == EVENT_TYPE_SERVERSIDE) - { - FIXME("Matching serverside events through navigation currently unimplemented\n"); - return S_OK; - } - V_VT(&prop_cond.Value) = VT_I4 | VT_ARRAY; V_ARRAY(&prop_cond.Value) = event->runtime_id;
@@ -1284,6 +1337,22 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia { HUIANODE node2 = NULL;
+ /* + * When trying to match serverside events through navigation, we + * don't want any clientside providers added in the server process. + * Once we encounter a provider with an HWND, we pass it off to the + * client for any further navigation. + */ + if (event->event_type == EVENT_TYPE_SERVERSIDE) + { + if (node_data->hwnd) + { + hr = uia_event_invoke(node, (HUIANODE)&node_data->IWineUiaNode_iface, args, event); + break; + } + set_refuse_hwnd_providers(node_data, TRUE); + } + hr = navigate_uia_node(node_data, NavigateDirection_Parent, &node2); IWineUiaNode_Release(&node_data->IWineUiaNode_iface); if (FAILED(hr) || !node2) @@ -1296,7 +1365,7 @@ static HRESULT uia_event_check_match(HUIANODE node, SAFEARRAY *rt_id, struct uia
if (uia_condition_matched(hr)) { - hr = uia_event_invoke(node, args, event); + hr = uia_event_invoke(node, NULL, args, event); break; }
@@ -1355,7 +1424,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve { struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry);
- hr = uia_event_check_match(node, sa, args, event); + hr = uia_event_check_match(node, node, sa, args, event); if (FAILED(hr)) break; } @@ -1366,7 +1435,7 @@ static HRESULT uia_raise_event(IRawElementProviderSimple *elprov, struct uia_eve { struct uia_event *event = LIST_ENTRY(cursor, struct uia_event, event_list_entry);
- hr = uia_event_check_match(node, sa, args, event); + hr = uia_event_check_match(node, node, sa, args, event); if (FAILED(hr)) break; }
This merge request was approved by Esme Povirk.