Initial patches for navigating between HUIANODEs.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 854 ++++++++++++++++++++ dlls/uiautomationcore/uia_client.c | 11 + dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 2 + 4 files changed, 868 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 91c9e75c46a..433cf64707b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -2165,6 +2165,26 @@ static struct Provider Provider_override = 0, 0, };
+#define DEFINE_PROVIDER(name) \ + static struct Provider Provider_ ## name = \ + { \ + { &ProviderSimpleVtbl }, \ + { &ProviderFragmentVtbl }, \ + { &ProviderFragmentRootVtbl }, \ + { &ProviderHwndOverrideVtbl }, \ + 1, \ + "Provider_" # name "", \ + NULL, NULL, \ + NULL, NULL, \ + NULL, NULL, \ + ProviderOptions_ServerSideProvider, 0, 0 \ + } + +DEFINE_PROVIDER(hwnd_child); +DEFINE_PROVIDER(hwnd_child2); +DEFINE_PROVIDER(nc_child); +DEFINE_PROVIDER(nc_child2); + static IAccessible *acc_client; static IRawElementProviderSimple *prov_root; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -7388,6 +7408,839 @@ static void test_UiaGetUpdatedCache(void) CoUninitialize(); }
+/* + * This sequence of method calls is always used when creating an HUIANODE from + * an IRawElementProviderSimple that returns an HWND from get_HostRawElementProvider. + */ +#define NODE_CREATE_SEQ2(prov) \ + { prov , PROV_GET_PROVIDER_OPTIONS }, \ + /* Win10v1507 and below call this. */ \ + { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ + { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, \ + { prov , FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ + +static const struct prov_method_sequence nav_seq1[] = { + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq2[] = { + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + NODE_CREATE_SEQ(&Provider_hwnd_child), + { &Provider_hwnd_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq3[] = { + { &Provider_hwnd_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_hwnd_child2), + { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq4[] = { + { &Provider_hwnd_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_hwnd_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* All Windows versions use the NativeWindowHandle provider type check here. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + { &Provider_nc_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_nc_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, + { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq5[] = { + { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_PreviousSibling */ + { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_nc, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + NODE_CREATE_SEQ(&Provider_hwnd_child2), + { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq6[] = { + { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_nc_child2), + { &Provider_nc_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq7[] = { + { &Provider_nc_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_nc_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_nc, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq8[] = { + { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_child2), + { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq9[] = { + { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + /* Navigates to parent a second time. */ + { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, +}; + +static const struct prov_method_sequence nav_seq10[] = { + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + NODE_CREATE_SEQ(&Provider_child2), + { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq11[] = { + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + { &Provider_hwnd_child, PROV_GET_PROVIDER_OPTIONS }, + /* All Windows versions use the NativeWindowHandle provider type check here. */ + { &Provider_hwnd_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_hwnd_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_hwnd_child2), + { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq12[] = { + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_child2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider_child2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_PreviousSibling */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq13[] = { + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Only done on Win10v1809+ */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* Windows 10+ calls these. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence nav_seq14[] = { + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider2), + { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static void set_provider_nav_ifaces(struct Provider *prov, struct Provider *parent, struct Provider *frag_root, + struct Provider *prev_sibling, struct Provider *next_sibling, struct Provider *first_child, + struct Provider *last_child) +{ + prov->parent = NULL; + prov->frag_root = NULL; + prov->prev_sibling = NULL; + prov->next_sibling = NULL; + prov->first_child = NULL; + prov->last_child = NULL; + + if (parent) + prov->parent = &parent->IRawElementProviderFragment_iface; + if (frag_root) + prov->frag_root = &frag_root->IRawElementProviderFragmentRoot_iface; + if (prev_sibling) + prov->prev_sibling = &prev_sibling->IRawElementProviderFragment_iface; + if (next_sibling) + prov->next_sibling = &next_sibling->IRawElementProviderFragment_iface; + if (first_child) + prov->first_child = &first_child->IRawElementProviderFragment_iface; + if (last_child) + prov->last_child = &last_child->IRawElementProviderFragment_iface; +} + +static void test_UiaNavigate(void) +{ + LONG exp_lbound[2], exp_elems[2], idx[2], i; + struct node_provider_desc exp_node_desc[4]; + struct UiaCacheRequest cache_req; + HUIANODE node, node2, node3; + SAFEARRAY *out_req; + BSTR tree_struct; + WNDCLASSA cls; + HRESULT hr; + VARIANT v; + HWND hwnd; + + CoInitializeEx(NULL, COINIT_MULTITHREADED); + cls.style = 0; + cls.lpfnWndProc = test_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "UiaNavigate class"; + + RegisterClassA(&cls); + + hwnd = CreateWindowA("UiaNavigate class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + UiaRegisterProviderCallback(test_uia_provider_callback); + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + + set_provider_nav_ifaces(&Provider_nc, NULL, NULL, NULL, NULL, &Provider_nc_child, &Provider_nc_child2); + set_provider_nav_ifaces(&Provider_nc_child, &Provider_nc, &Provider_nc, NULL, + &Provider_nc_child2, NULL, NULL); + set_provider_nav_ifaces(&Provider_nc_child2, &Provider_nc, &Provider_nc, &Provider_nc_child, + NULL, NULL, NULL); + + set_provider_nav_ifaces(&Provider_hwnd, NULL, NULL, NULL, NULL, &Provider_hwnd_child, &Provider_hwnd_child2); + set_provider_nav_ifaces(&Provider_hwnd_child, &Provider_hwnd, &Provider_hwnd, NULL, + &Provider_hwnd_child2, NULL, NULL); + set_provider_nav_ifaces(&Provider_hwnd_child2, &Provider_hwnd, &Provider_hwnd, &Provider_hwnd_child, + NULL, NULL, NULL); + + /* + * Show navigation behavior for multi-provider nodes. Navigation order is: + * HWND provider children. + * Non-Client provider children. + * Main provider children. + * Override provider children. + */ + Provider.prov_opts = ProviderOptions_ServerSideProvider; + Provider.hwnd = Provider_hwnd.hwnd = Provider_nc.hwnd = hwnd; + Provider.ignore_hwnd_prop = Provider_nc.ignore_hwnd_prop = TRUE; + prov_root = &Provider.IRawElementProviderSimple_iface; + node = (void *)0xdeadbeef; + /* Only sent on Win7. */ + SET_EXPECT(winproc_GETOBJECT_CLIENT); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + hr = UiaNodeFromHandle(hwnd, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + VariantClear(&v); + } + + ok_method_sequence(nav_seq1, "nav_seq1"); + + for (i = 0; i < ARRAY_SIZE(exp_node_desc); i++) + init_node_provider_desc(&exp_node_desc[i], GetCurrentProcessId(), NULL); + idx[0] = idx[1] = 0; + + /* Navigate to Provider_hwnd_child. */ + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child", TRUE); + set_cache_request(&cache_req, NULL, TreeScope_Element, NULL, 0, NULL, 0, AutomationElementMode_Full); + tree_struct = NULL; out_req = NULL; + hr = UiaNavigate(node, NavigateDirection_FirstChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_hwnd_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); + + node2 = node3 = NULL; + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq2, "nav_seq2"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + /* Navigate to Provider_hwnd_child2. */ + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child2", TRUE); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq3, "nav_seq3"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_hwnd_child.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); + node2 = node3; + + /* Navigate to Provider_nc_child. */ + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_nc_child", TRUE); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_nc_child.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child.ref); + todo_wine CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq4, "nav_seq4"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + node2 = node3; + + /* Navigate back to Provider_hwnd_child2. */ + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child2", TRUE); + hr = UiaNavigate(node2, NavigateDirection_PreviousSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + todo_wine CHECK_CALLED(prov_callback_base_hwnd); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq5, "nav_seq5"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node3), "UiaNodeRelease returned FALSE\n"); + ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + + /* Navigate to Provider_nc_child2. */ + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_nc_child2", TRUE); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_nc_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child2.ref); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq6, "nav_seq6"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_nc_child.ref == 1, "Unexpected refcnt %ld\n", Provider_nc_child.ref); + node2 = node3; + + /* Navigate to Provider_child. */ + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child", TRUE); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + todo_wine CHECK_CALLED(prov_callback_base_hwnd); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq7, "nav_seq7"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_nc_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_nc_child2.ref); + node2 = node3; + + /* Navigate to Provider_child2. */ + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child2", TRUE); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq8, "nav_seq8"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + node2 = node3; + + /* Try navigating to next sibling on the final child of the node. */ + SET_EXPECT_MULTI(prov_callback_nonclient, 2); + SET_EXPECT_MULTI(prov_callback_base_hwnd, 2); + SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); + hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + ok_method_sequence(nav_seq9, "nav_seq9"); + ok(!out_req, "out_req != NULL\n"); + ok(!tree_struct, "tree_struct != NULL\n"); + todo_wine CHECK_CALLED_MULTI(prov_callback_nonclient, 2); + todo_wine CHECK_CALLED_MULTI(prov_callback_base_hwnd, 2); + todo_wine CHECK_CALLED_MULTI(winproc_GETOBJECT_UiaRoot, 2); + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + + /* Navigate to Provider_child2, last child. */ + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child2", TRUE); + set_cache_request(&cache_req, NULL, TreeScope_Element, NULL, 0, NULL, 0, AutomationElementMode_Full); + tree_struct = NULL; + out_req = NULL; + hr = UiaNavigate(node, NavigateDirection_LastChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); + + if (out_req) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq10, "nav_seq10"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + /* + * If the child we navigate to from a parent isn't considered the "parent + * link" of it's HUIANODE, it is skipped. Here, we set Provider_hwnd_child + * to an HWND provider, and set its main provider as Provider, which is + * the parent link of the node. + */ + Provider_hwnd_child.hwnd = hwnd; + Provider_hwnd_child.prov_opts = ProviderOptions_ClientSideProvider; + Provider.parent = &Provider2.IRawElementProviderFragment_iface; + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child2", TRUE); + tree_struct = NULL; + out_req = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_nonclient); + hr = UiaNavigate(node, NavigateDirection_FirstChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + todo_wine CHECK_CALLED(prov_callback_nonclient); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq11, "nav_seq11"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + + /* + * Same test as before, except with NavigateDirection_LastChild. This will + * end up with Provider_nc as the parent link for the node instead of + * Provider_child2. + */ + Provider_child2.hwnd = hwnd; + Provider_child2.ignore_hwnd_prop = TRUE; + Provider_child2.parent = NULL; + Provider_nc.parent = &Provider2.IRawElementProviderFragment_iface; + Provider2.prov_opts = ProviderOptions_ServerSideProvider; + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child", TRUE); + tree_struct = NULL; + out_req = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_base_hwnd); + hr = UiaNavigate(node, NavigateDirection_LastChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + todo_wine CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(prov_callback_base_hwnd); + + if (out_req) + { + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2); + + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq12, "nav_seq12"); + } + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + + todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + + Provider_child2.hwnd = NULL; + Provider_child2.ignore_hwnd_prop = FALSE; + Provider_child2.parent = &Provider.IRawElementProviderFragment_iface; + + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + + /* Create a node with Provider_nc as the parent link. */ + Provider.parent = Provider_hwnd.parent = NULL; + Provider_nc.parent = &Provider2.IRawElementProviderFragment_iface; + Provider2.prov_opts = ProviderOptions_ServerSideProvider; + Provider2.hwnd = NULL; + + node = (void *)0xdeadbeef; + /* Only sent on Win7. */ + SET_EXPECT(winproc_GETOBJECT_CLIENT); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + hr = UiaNodeFromHandle(hwnd, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + VariantClear(&v); + } + + ok_method_sequence(nav_seq13, "nav_seq13"); + + /* Navigate to Provider2, parent of Provider_nc. */ + init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); + add_provider_desc(&exp_node_desc[0], L"Main", L"Provider2", TRUE); + set_cache_request(&cache_req, NULL, TreeScope_Element, NULL, 0, NULL, 0, AutomationElementMode_Full); + tree_struct = NULL; + out_req = NULL; + hr = UiaNavigate(node, NavigateDirection_Parent, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + todo_wine ok(!!out_req, "out_req == NULL\n"); + todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); + todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); + + if (SUCCEEDED(hr)) + { + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); + ok_method_sequence(nav_seq14, "nav_seq14"); + } + + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + + Provider_hwnd_child.hwnd = NULL; + Provider_hwnd_child.prov_opts = ProviderOptions_ServerSideProvider; + Provider.ignore_hwnd_prop = Provider_nc.ignore_hwnd_prop = FALSE; + base_hwnd_prov = nc_prov = NULL; + prov_root = NULL; + UiaRegisterProviderCallback(NULL); + + CoUninitialize(); + DestroyWindow(hwnd); + UnregisterClassA("UiaNavigate class", NULL); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -7452,6 +8305,7 @@ START_TEST(uiautomation) launch_test_process(argv[0], "UiaNodeFromHandle"); launch_test_process(argv[0], "UiaRegisterProviderCallback"); test_UiaGetUpdatedCache(); + test_UiaNavigate(); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 11a6e3ffc45..3902d879825 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2127,3 +2127,14 @@ HRESULT WINAPI UiaGetUpdatedCache(HUIANODE huianode, struct UiaCacheRequest *cac
return S_OK; } + +/*********************************************************************** + * UiaNavigate (uiautomationcore.@) + */ +HRESULT WINAPI UiaNavigate(HUIANODE huianode, enum NavigateDirection dir, struct UiaCondition *nav_condition, + struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct) +{ + FIXME("(%p, %u, %p, %p, %p, %p): stub\n", huianode, dir, nav_condition, cache_req, out_req, + tree_struct); + return E_NOTIMPL; +} diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 56d1d33bd2b..c14b457fd47 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -75,7 +75,7 @@ @ stdcall UiaHostProviderFromHwnd(long ptr) #@ stub UiaIAccessibleFromProvider @ stdcall UiaLookupId(long ptr) -@ stub UiaNavigate +@ stdcall UiaNavigate(ptr long ptr ptr ptr ptr) @ stub UiaNodeFromFocus @ stdcall UiaNodeFromHandle(long ptr) @ stub UiaNodeFromPoint diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index ecac43b7c01..7025392cbbc 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -407,6 +407,8 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode); HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov); HRESULT WINAPI UiaGetUpdatedCache(HUIANODE huianode, struct UiaCacheRequest *cache_req, enum NormalizeState normalize_state, struct UiaCondition *normalize_cond, SAFEARRAY **out_req, BSTR *tree_struct); +HRESULT WINAPI UiaNavigate(HUIANODE huianode, enum NavigateDirection dir, struct UiaCondition *nav_condition, + struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct);
#ifdef __cplusplus }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 112 ++++++++++----------- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 88 +++++++++++++++- dlls/uiautomationcore/uia_private.h | 3 + 4 files changed, 147 insertions(+), 57 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 433cf64707b..15368a7fd03 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4048,7 +4048,7 @@ static const struct prov_method_sequence node_from_prov2[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -4061,7 +4061,7 @@ static const struct prov_method_sequence node_from_prov3[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -4073,7 +4073,7 @@ static const struct prov_method_sequence node_from_prov4[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -4089,12 +4089,12 @@ static const struct prov_method_sequence node_from_prov5[] = { /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These three are only done on Win10v1507 and below. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider2, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* This is only done on Win10v1507. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only called on Windows versions past Win10v1507. */ @@ -4114,13 +4114,13 @@ static const struct prov_method_sequence node_from_prov6[] = { /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider2, PROV_GET_PROVIDER_OPTIONS }, { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Only called on Windows versions past Win10v1507. */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider2, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* This is only done on Win10v1507. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only called on Windows versions past Win10v1507. */ @@ -4139,13 +4139,13 @@ static const struct prov_method_sequence node_from_prov7[] = { /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider2, PROV_GET_PROVIDER_OPTIONS }, { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Only called on Windows versions past Win10v1507. */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider2, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* This is only done on Win10v1507. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only called on Windows versions past Win10v1507. */ @@ -4161,7 +4161,7 @@ static const struct prov_method_sequence node_from_prov8[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { 0 } @@ -4537,7 +4537,7 @@ static const struct prov_method_sequence get_elem_prop_seq[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, @@ -4552,14 +4552,14 @@ static const struct prov_method_sequence get_elem_arr_prop_seq[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child2, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, { &Provider_child2, PROV_GET_PROPERTY_VALUE }, @@ -5196,10 +5196,10 @@ static const struct prov_method_sequence node_from_hwnd2[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls this. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -5211,7 +5211,7 @@ static const struct prov_method_sequence node_from_hwnd3[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -5225,7 +5225,7 @@ static const struct prov_method_sequence node_from_hwnd4[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Only called on Windows versions past Win10v1507. */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ @@ -5240,7 +5240,7 @@ static const struct prov_method_sequence node_from_hwnd5[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Only done in Windows 8+. */ { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, @@ -5258,7 +5258,7 @@ static const struct prov_method_sequence node_from_hwnd6[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Next 4 are only done in Windows 8+. */ { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, @@ -5283,13 +5283,13 @@ static const struct prov_method_sequence node_from_hwnd7[] = { /* Win10v1507 and below call this. */ { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ @@ -5301,7 +5301,7 @@ static const struct prov_method_sequence node_from_hwnd8[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ @@ -5315,7 +5315,7 @@ static const struct prov_method_sequence node_from_hwnd9[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done in Windows 8+. */ { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, @@ -5333,7 +5333,7 @@ static const struct prov_method_sequence disconnect_prov1[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, FRAG_GET_RUNTIME_ID }, { &Provider_child, FRAG_GET_FRAGMENT_ROOT }, @@ -5348,7 +5348,7 @@ static const struct prov_method_sequence disconnect_prov2[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_FRAGMENT_ROOT }, @@ -5361,7 +5361,7 @@ static const struct prov_method_sequence disconnect_prov3[] = { { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, FRAG_GET_RUNTIME_ID }, { 0 } @@ -5372,7 +5372,7 @@ static const struct prov_method_sequence disconnect_prov4[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { 0 } }; @@ -6071,7 +6071,7 @@ static void test_UiaNodeFromHandle(const char *name) }
static const struct prov_method_sequence reg_prov_cb1[] = { - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } @@ -6081,7 +6081,7 @@ static const struct prov_method_sequence reg_prov_cb2[] = { /* These two are only done on Win10v1809+. */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } @@ -6092,9 +6092,9 @@ static const struct prov_method_sequence reg_prov_cb3[] = { /* These two are only done on Win10v1809+. */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These three only done on Win10+. */ { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -6111,9 +6111,9 @@ static const struct prov_method_sequence reg_prov_cb4[] = { { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These four only done on Win10+. */ { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -6176,9 +6176,9 @@ static const struct prov_method_sequence reg_prov_cb10[] = { { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These four only done on Win10+. */ { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -6192,16 +6192,16 @@ static const struct prov_method_sequence reg_prov_cb11[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, /* These two are only done on Win10v1809+. */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These three only done on Win10+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -6217,7 +6217,7 @@ static const struct prov_method_sequence reg_prov_cb12[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, @@ -6231,9 +6231,9 @@ static const struct prov_method_sequence reg_prov_cb12[] = { /* These two are only done on Win10v1809+. */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* These three only done on Win10+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -6249,7 +6249,7 @@ static const struct prov_method_sequence reg_prov_cb13[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, @@ -6271,9 +6271,9 @@ static const struct prov_method_sequence reg_prov_cb13[] = { { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ /* Only done on Win10v1809+. */ { &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ /* These three only done on Win10+. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -7417,7 +7417,7 @@ static void test_UiaGetUpdatedCache(void) /* Win10v1507 and below call this. */ \ { prov , PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ \ { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, \ - { prov , FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ \ + { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \
static const struct prov_method_sequence nav_seq1[] = { @@ -7425,9 +7425,9 @@ static const struct prov_method_sequence nav_seq1[] = { { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -7641,8 +7641,8 @@ static const struct prov_method_sequence nav_seq13[] = { { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index a240534222a..d8982259050 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -45,6 +45,7 @@ library UIA_wine_private { HRESULT get_prop_val([in]const struct uia_prop_info *prop_info, [out, retval]VARIANT *ret_val); HRESULT get_prov_opts([out, retval]int *out_opts); + HRESULT has_parent([out, retval]BOOL *out_val); }
[ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 3902d879825..d053b88dd11 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -355,6 +355,22 @@ static HRESULT get_prov_opts_from_node_provider(IWineUiaNode *node, int idx, int return hr; }
+static HRESULT get_has_parent_from_node_provider(IWineUiaNode *node, int idx, BOOL *out_val) +{ + IWineUiaProvider *prov; + HRESULT hr; + + *out_val = FALSE; + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_has_parent(prov, out_val); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -561,7 +577,33 @@ static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface) static BOOL is_nested_node_provider(IWineUiaProvider *iface); static HRESULT prepare_uia_node(struct uia_node *node) { - int i; + int i, prov_idx; + HRESULT hr; + + /* + * HUIANODEs can only have one 'parent link' provider, which handles + * parent and sibling navigation for the entire HUIANODE. Each provider is + * queried for a parent in descending order, starting with the override + * provider. The first provider to have a valid parent is made parent + * link. If no providers return a valid parent, the provider at index 0 + * is made parent link by default. + */ + for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++) + { + BOOL has_parent; + + if (!node->prov[i]) + continue; + + hr = get_has_parent_from_node_provider(&node->IWineUiaNode_iface, prov_idx, &has_parent); + if (SUCCEEDED(hr) && has_parent) + { + node->parent_link_idx = prov_idx; + break; + } + + prov_idx++; + }
for (i = 0; i < PROV_TYPE_COUNT; i++) { @@ -889,12 +931,45 @@ static HRESULT WINAPI uia_provider_get_prov_opts(IWineUiaProvider *iface, int *o return S_OK; }
+static HRESULT WINAPI uia_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val) +{ + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + + TRACE("%p, %p\n", iface, out_val); + + if (!prov->parent_check_ran) + { + IRawElementProviderFragment *elfrag, *elfrag2; + HRESULT hr; + + prov->has_parent = FALSE; + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + if (SUCCEEDED(hr) && elfrag) + { + hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2); + IRawElementProviderFragment_Release(elfrag); + if (SUCCEEDED(hr) && elfrag2) + { + prov->has_parent = TRUE; + IRawElementProviderFragment_Release(elfrag2); + } + } + + prov->parent_check_ran = TRUE; + } + + *out_val = prov->has_parent; + + return S_OK; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, uia_provider_Release, uia_provider_get_prop_val, uia_provider_get_prov_opts, + uia_provider_has_parent, };
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -1260,12 +1335,22 @@ static HRESULT WINAPI uia_nested_node_provider_get_prov_opts(IWineUiaProvider *i return get_prov_opts_from_node_provider(prov->nested_node, 0, out_opts); }
+static HRESULT WINAPI uia_nested_node_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val) +{ + struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface); + + TRACE("%p, %p\n", iface, out_val); + + return get_has_parent_from_node_provider(prov->nested_node, 0, out_val); +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, uia_nested_node_provider_Release, uia_nested_node_provider_get_prop_val, uia_nested_node_provider_get_prov_opts, + uia_nested_node_provider_has_parent, };
static BOOL is_nested_node_provider(IWineUiaProvider *iface) @@ -1340,6 +1425,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->return_nested_node = FALSE; + prov_data->parent_check_ran = FALSE;
IWineUiaNode_Release(nested_node); uia_stop_client_thread(); diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 39c9aac847b..cb4ce8b0acf 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -59,6 +59,7 @@ struct uia_node { IWineUiaProvider *prov[PROV_TYPE_COUNT]; DWORD git_cookie[PROV_TYPE_COUNT]; int prov_count; + int parent_link_idx;
HWND hwnd; BOOL nested_node; @@ -79,6 +80,8 @@ struct uia_provider {
IRawElementProviderSimple *elprov; BOOL return_nested_node; + BOOL parent_check_ran; + BOOL has_parent; };
static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *iface)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_client.c | 48 +++++++++++++++++++----------- 1 file changed, 31 insertions(+), 17 deletions(-)
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index d053b88dd11..8f9ac813a8d 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -694,6 +694,34 @@ static void get_variant_for_node(HUIANODE node, VARIANT *v) #endif }
+static HRESULT get_variant_for_elprov_node(IRawElementProviderSimple *elprov, BOOL out_nested, + VARIANT *v) +{ + HUIANODE node; + HRESULT hr; + + VariantInit(v); + hr = create_uia_node_from_elprov(elprov, &node, !out_nested); + IRawElementProviderSimple_Release(elprov); + if (SUCCEEDED(hr)) + { + if (out_nested) + { + LRESULT lr = uia_lresult_from_node(node); + + if (!lr) + return E_FAIL; + + V_VT(v) = VT_I4; + V_I4(v) = lr; + } + else + get_variant_for_node(node, v); + } + + return S_OK; +} + static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, const struct uia_prop_info *prop_info, VARIANT *ret_val) { @@ -764,7 +792,6 @@ static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, case UIAutomationType_Element: { IRawElementProviderSimple *elprov; - HUIANODE node;
if (V_VT(&v) != VT_UNKNOWN) { @@ -778,23 +805,10 @@ static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, if (FAILED(hr)) goto exit;
- hr = create_uia_node_from_elprov(elprov, &node, !prov->return_nested_node); - IRawElementProviderSimple_Release(elprov); - if (SUCCEEDED(hr)) - { - if (prov->return_nested_node) - { - LRESULT lr = uia_lresult_from_node(node); - - if (!lr) - return E_FAIL; + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, ret_val); + if (FAILED(hr)) + return hr;
- V_VT(ret_val) = VT_I4; - V_I4(ret_val) = lr; - } - else - get_variant_for_node(node, ret_val); - } break; }
From: Connor McAdams cmcadams@codeweavers.com
Add support for navigating between siblings of an individual IWineUiaProvider for an HUIANODE.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_client.c | 92 +++++++++++++++++++++++++++-- dlls/uiautomationcore/uia_private.h | 2 + 2 files changed, 88 insertions(+), 6 deletions(-)
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 23a0dc3d3c4..4d13262e292 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -596,6 +596,18 @@ static HRESULT prepare_uia_node(struct uia_node *node) int i, prov_idx; HRESULT hr;
+ /* Get the provider index for the provider that created the node. */ + for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++) + { + if (i == node->creator_prov_type) + { + node->creator_prov_idx = prov_idx; + break; + } + else if (node->prov[i]) + prov_idx++; + } + /* * HUIANODEs can only have one 'parent link' provider, which handles * parent and sibling navigation for the entire HUIANODE. Each provider is @@ -659,6 +671,62 @@ static HRESULT prepare_uia_node(struct uia_node *node) return S_OK; }
+static BOOL node_creator_is_parent_link(struct uia_node *node) +{ + if (node->creator_prov_idx == node->parent_link_idx) + return TRUE; + else + return FALSE; +} + +static HRESULT get_sibling_from_node_provider(struct uia_node *node, int prov_idx, int nav_dir, + VARIANT *out_node) +{ + HUIANODE tmp_node; + HRESULT hr; + VARIANT v; + + hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, prov_idx, nav_dir, &v); + if (FAILED(hr)) + return hr; + + hr = UiaHUiaNodeFromVariant(&v, &tmp_node); + if (FAILED(hr)) + goto exit; + + while (1) + { + struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)tmp_node); + + /* + * If our sibling provider is the parent link of it's HUIANODE, then + * it is a valid sibling of this node. + */ + if (node_creator_is_parent_link(node_data)) + break; + + /* + * If our sibling provider is not the parent link of it's HUIANODE, we + * need to try the next sibling. + */ + hr = get_navigate_from_node_provider((IWineUiaNode *)tmp_node, node_data->creator_prov_idx, nav_dir, &v); + UiaNodeRelease(tmp_node); + if (FAILED(hr)) + return hr; + + tmp_node = NULL; + hr = UiaHUiaNodeFromVariant(&v, &tmp_node); + if (FAILED(hr)) + break; + } + +exit: + if (tmp_node) + *out_node = v; + + return S_OK; +} + static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) { HRESULT hr; @@ -671,19 +739,20 @@ static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *o { case NavigateDirection_FirstChild: case NavigateDirection_LastChild: - case NavigateDirection_NextSibling: - case NavigateDirection_PreviousSibling: FIXME("Unimplemented NavigateDirection %d\n", nav_dir); return E_NOTIMPL;
+ case NavigateDirection_NextSibling: + case NavigateDirection_PreviousSibling: + hr = get_sibling_from_node_provider(node, node->parent_link_idx, nav_dir, &v); + if (FAILED(hr)) + WARN("Sibling navigation failed with hr %#lx\n", hr); + break; + case NavigateDirection_Parent: hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx, nav_dir, &v); if (FAILED(hr)) WARN("Parent navigation failed with hr %#lx\n", hr); - - hr = UiaHUiaNodeFromVariant(&v, out_node); - if (FAILED(hr)) - *out_node = NULL; break;
default: @@ -691,6 +760,13 @@ static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *o return E_INVALIDARG; }
+ if (V_VT(&v) != VT_EMPTY) + { + hr = UiaHUiaNodeFromVariant(&v, (HUIANODE *)out_node); + if (FAILED(hr)) + WARN("UiaHUiaNodeFromVariant failed with hr %#lx\n", hr); + } + return S_OK; }
@@ -1082,6 +1158,8 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid prov->elprov = elprov; prov->ref = 1; node->prov[prov_type] = &prov->IWineUiaProvider_iface; + if (!node->prov_count) + node->creator_prov_type = prov_type; node->prov_count++;
IRawElementProviderSimple_AddRef(elprov); @@ -1595,6 +1673,8 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU
node->prov[prov_type] = provider_iface; node->git_cookie[prov_type] = git_cookie; + if (!node->prov_count) + node->creator_prov_type = prov_type; node->prov_count++;
return S_OK; diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index cb4ce8b0acf..63820d0b937 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -60,10 +60,12 @@ struct uia_node { DWORD git_cookie[PROV_TYPE_COUNT]; int prov_count; int parent_link_idx; + int creator_prov_idx;
HWND hwnd; BOOL nested_node; BOOL disconnected; + int creator_prov_type; struct list prov_thread_list_entry; struct list node_map_list_entry; struct uia_provider_thread_map_entry *map;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 27 ++-- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 142 ++++++++++++++++++++- 3 files changed, 153 insertions(+), 17 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 15368a7fd03..d5c186e7ee6 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -8205,24 +8205,21 @@ static void test_UiaNavigate(void) tree_struct = NULL; out_req = NULL; hr = UiaNavigate(node, NavigateDirection_Parent, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref);
- if (SUCCEEDED(hr)) - { - exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct));
- SafeArrayDestroy(out_req); - SysFreeString(tree_struct); - ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); - ok_method_sequence(nav_seq14, "nav_seq14"); - } + SafeArrayDestroy(out_req); + SysFreeString(tree_struct); + ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); + ok_method_sequence(nav_seq14, "nav_seq14");
ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index d8982259050..2dc7981b702 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -46,6 +46,7 @@ library UIA_wine_private HRESULT get_prop_val([in]const struct uia_prop_info *prop_info, [out, retval]VARIANT *ret_val); HRESULT get_prov_opts([out, retval]int *out_opts); HRESULT has_parent([out, retval]BOOL *out_val); + HRESULT navigate([in]int nav_dir, [out, retval]VARIANT *ret_val); }
[ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 8f9ac813a8d..23a0dc3d3c4 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -371,6 +371,22 @@ static HRESULT get_has_parent_from_node_provider(IWineUiaNode *node, int idx, BO return hr; }
+static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int nav_dir, VARIANT *ret_val) +{ + IWineUiaProvider *prov; + HRESULT hr; + + VariantInit(ret_val); + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_navigate(prov, nav_dir, ret_val); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -643,6 +659,41 @@ static HRESULT prepare_uia_node(struct uia_node *node) return S_OK; }
+static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) +{ + HRESULT hr; + VARIANT v; + + *out_node = NULL; + + VariantInit(&v); + switch (nav_dir) + { + case NavigateDirection_FirstChild: + case NavigateDirection_LastChild: + case NavigateDirection_NextSibling: + case NavigateDirection_PreviousSibling: + FIXME("Unimplemented NavigateDirection %d\n", nav_dir); + return E_NOTIMPL; + + case NavigateDirection_Parent: + hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx, nav_dir, &v); + if (FAILED(hr)) + WARN("Parent navigation failed with hr %#lx\n", hr); + + hr = UiaHUiaNodeFromVariant(&v, out_node); + if (FAILED(hr)) + *out_node = NULL; + break; + + default: + WARN("Invalid NavigateDirection %d\n", nav_dir); + return E_INVALIDARG; + } + + return S_OK; +} + /* * IWineUiaProvider interface. */ @@ -977,6 +1028,38 @@ static HRESULT WINAPI uia_provider_has_parent(IWineUiaProvider *iface, BOOL *out return S_OK; }
+static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val) +{ + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + IRawElementProviderFragment *elfrag, *elfrag2; + HRESULT hr; + + TRACE("%p, %d, %p\n", iface, nav_dir, out_val); + + VariantInit(out_val); + hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag); + if (FAILED(hr) || !elfrag) + return S_OK; + + hr = IRawElementProviderFragment_Navigate(elfrag, nav_dir, &elfrag2); + IRawElementProviderFragment_Release(elfrag); + if (SUCCEEDED(hr) && elfrag2) + { + IRawElementProviderSimple *elprov; + + hr = IRawElementProviderFragment_QueryInterface(elfrag2, &IID_IRawElementProviderSimple, (void **)&elprov); + IRawElementProviderFragment_Release(elfrag2); + if (FAILED(hr) || !elprov) + return hr; + + hr = get_variant_for_elprov_node(elprov, prov->return_nested_node, out_val); + if (FAILED(hr)) + return hr; + } + + return S_OK; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, @@ -984,6 +1067,7 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_get_prop_val, uia_provider_get_prov_opts, uia_provider_has_parent, + uia_provider_navigate, };
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -1358,6 +1442,30 @@ static HRESULT WINAPI uia_nested_node_provider_has_parent(IWineUiaProvider *ifac return get_has_parent_from_node_provider(prov->nested_node, 0, out_val); }
+static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val) +{ + struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface); + HUIANODE node; + HRESULT hr; + VARIANT v; + + TRACE("%p, %d, %p\n", iface, nav_dir, out_val); + + VariantInit(out_val); + hr = get_navigate_from_node_provider(prov->nested_node, 0, nav_dir, &v); + if (FAILED(hr) || V_VT(&v) == VT_EMPTY) + return hr; + + hr = uia_node_from_lresult((LRESULT)V_I4(&v), &node); + if (FAILED(hr)) + return hr; + + get_variant_for_node(node, out_val); + VariantClear(&v); + + return S_OK; +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, @@ -1365,6 +1473,7 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_get_prop_val, uia_nested_node_provider_get_prov_opts, uia_nested_node_provider_has_parent, + uia_nested_node_provider_navigate, };
static BOOL is_nested_node_provider(IWineUiaProvider *iface) @@ -2234,7 +2343,36 @@ HRESULT WINAPI UiaGetUpdatedCache(HUIANODE huianode, struct UiaCacheRequest *cac HRESULT WINAPI UiaNavigate(HUIANODE huianode, enum NavigateDirection dir, struct UiaCondition *nav_condition, struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct) { - FIXME("(%p, %u, %p, %p, %p, %p): stub\n", huianode, dir, nav_condition, cache_req, out_req, + struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode); + HUIANODE node2; + HRESULT hr; + + TRACE("(%p, %u, %p, %p, %p, %p)\n", huianode, dir, nav_condition, cache_req, out_req, tree_struct); - return E_NOTIMPL; + + if (!node || !nav_condition || !cache_req || !out_req || !tree_struct) + return E_INVALIDARG; + + *out_req = NULL; + *tree_struct = NULL; + + if (nav_condition->ConditionType != ConditionType_True) + { + FIXME("ConditionType %d based navigation is not implemented.\n", nav_condition->ConditionType); + return E_NOTIMPL; + } + + hr = navigate_uia_node(node, dir, &node2); + if (FAILED(hr)) + return hr; + + if (node2) + { + hr = UiaGetUpdatedCache(node2, cache_req, NormalizeState_None, NULL, out_req, tree_struct); + if (FAILED(hr)) + WARN("UiaGetUpdatedCache failed with hr %#lx\n", hr); + UiaNodeRelease(node2); + } + + return hr; }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 187 ++++++++++----------- dlls/uiautomationcore/uia_client.c | 68 +++++++- 2 files changed, 153 insertions(+), 102 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index d5c186e7ee6..1c6902cc498 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -7439,21 +7439,21 @@ static const struct prov_method_sequence nav_seq1[] = { };
static const struct prov_method_sequence nav_seq2[] = { - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ NODE_CREATE_SEQ(&Provider_hwnd_child), { &Provider_hwnd_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq3[] = { - { &Provider_hwnd_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_hwnd_child, FRAG_NAVIGATE}, /* NavigateDirection_NextSibling */ NODE_CREATE_SEQ(&Provider_hwnd_child2), { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq4[] = { - { &Provider_hwnd_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_hwnd_child2, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ { &Provider_hwnd_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, /* All Windows versions use the NativeWindowHandle provider type check here. */ @@ -7588,14 +7588,14 @@ static const struct prov_method_sequence nav_seq9[] = { };
static const struct prov_method_sequence nav_seq10[] = { - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_LastChild */ NODE_CREATE_SEQ(&Provider_child2), { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq11[] = { - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ { &Provider_hwnd_child, PROV_GET_PROVIDER_OPTIONS }, /* All Windows versions use the NativeWindowHandle provider type check here. */ { &Provider_hwnd_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_NativeWindowHandlePropertyId */ @@ -7604,19 +7604,19 @@ static const struct prov_method_sequence nav_seq11[] = { { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_hwnd_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider_hwnd_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_hwnd_child, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ NODE_CREATE_SEQ(&Provider_hwnd_child2), { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq12[] = { - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_LastChild */ { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, @@ -7630,7 +7630,7 @@ static const struct prov_method_sequence nav_seq12[] = { { &Provider_child2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_PreviousSibling */ + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_PreviousSibling */ NODE_CREATE_SEQ(&Provider_child), { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } @@ -7780,28 +7780,25 @@ static void test_UiaNavigate(void) set_cache_request(&cache_req, NULL, TreeScope_Element, NULL, 0, NULL, 0, AutomationElementMode_Full); tree_struct = NULL; out_req = NULL; hr = UiaNavigate(node, NavigateDirection_FirstChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_hwnd_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_hwnd_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref);
node2 = node3 = NULL; - if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node2); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node2); + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq2, "nav_seq2"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq2, "nav_seq2");
SafeArrayDestroy(out_req); SysFreeString(tree_struct); @@ -7810,32 +7807,29 @@ static void test_UiaNavigate(void) init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child2", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq3, "nav_seq3"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq3, "nav_seq3");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_hwnd_child.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); node2 = node3;
@@ -7845,13 +7839,14 @@ static void test_UiaNavigate(void) init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_nc_child", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); todo_wine ok(!!out_req, "out_req == NULL\n"); todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); todo_wine ok(Provider_nc_child.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child.ref); todo_wine CHECK_CALLED(prov_callback_nonclient); todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
+ node3 = NULL; if (out_req) { hr = SafeArrayGetElement(out_req, idx, &v); @@ -7866,13 +7861,14 @@ static void test_UiaNavigate(void) test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq4, "nav_seq4"); }
+ ok_method_sequence(nav_seq4, "nav_seq4"); + SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); node2 = node3;
@@ -8041,20 +8037,17 @@ static void test_UiaNavigate(void) tree_struct = NULL; out_req = NULL; hr = UiaNavigate(node, NavigateDirection_LastChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child.ref);
- if (out_req) - { - exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq10, "nav_seq10"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq10, "nav_seq10");
SafeArrayDestroy(out_req); SysFreeString(tree_struct); @@ -8075,34 +8068,31 @@ static void test_UiaNavigate(void) SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT(prov_callback_nonclient); hr = UiaNavigate(node, NavigateDirection_FirstChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(prov_callback_nonclient); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_nonclient);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node2); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node2); + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq11, "nav_seq11"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq11, "nav_seq11");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref);
/* @@ -8123,35 +8113,32 @@ static void test_UiaNavigate(void) SET_EXPECT(prov_callback_nonclient); SET_EXPECT(prov_callback_base_hwnd); hr = UiaNavigate(node, NavigateDirection_LastChild, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - todo_wine CHECK_CALLED(prov_callback_nonclient); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_base_hwnd);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node2); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node2); + hr = UiaHUiaNodeFromVariant(&v, &node2); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node2);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq12, "nav_seq12"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq12, "nav_seq12");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref);
Provider_child2.hwnd = NULL; diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 4d13262e292..0c58ef0aca0 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -727,6 +727,64 @@ exit: return S_OK; }
+static HRESULT get_child_for_node(struct uia_node *node, int start_prov_idx, int nav_dir, VARIANT *out_node) +{ + int prov_idx = start_prov_idx; + HUIANODE tmp_node = NULL; + HRESULT hr; + VARIANT v; + + while ((prov_idx >= 0) && (prov_idx < node->prov_count)) + { + struct uia_node *node_data; + + hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, prov_idx, nav_dir, &v); + if (FAILED(hr)) + return hr; + + if (nav_dir == NavigateDirection_FirstChild) + prov_idx--; + else + prov_idx++; + + /* If we failed to get a child, try the next provider. */ + hr = UiaHUiaNodeFromVariant(&v, &tmp_node); + if (FAILED(hr)) + continue; + + node_data = impl_from_IWineUiaNode((IWineUiaNode *)tmp_node); + + /* This child is the parent link of its node, so we can return it. */ + if (node_creator_is_parent_link(node_data)) + break; + + /* + * If the first child provider isn't the parent link of it's HUIANODE, + * we need to check the child provider for any valid siblings. + */ + if (nav_dir == NavigateDirection_FirstChild) + hr = get_sibling_from_node_provider(node_data, node_data->creator_prov_idx, + NavigateDirection_NextSibling, &v); + else + hr = get_sibling_from_node_provider(node_data, node_data->creator_prov_idx, + NavigateDirection_PreviousSibling, &v); + + UiaNodeRelease(tmp_node); + if (FAILED(hr)) + return hr; + + /* If we got a valid sibling from the child provider, return it. */ + hr = UiaHUiaNodeFromVariant(&v, &tmp_node); + if (SUCCEEDED(hr)) + break; + } + + if (tmp_node) + *out_node = v; + + return S_OK; +} + static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node) { HRESULT hr; @@ -739,8 +797,14 @@ static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *o { case NavigateDirection_FirstChild: case NavigateDirection_LastChild: - FIXME("Unimplemented NavigateDirection %d\n", nav_dir); - return E_NOTIMPL; + /* First child always comes from last provider index. */ + if (nav_dir == NavigateDirection_FirstChild) + hr = get_child_for_node(node, node->prov_count - 1, nav_dir, &v); + else + hr = get_child_for_node(node, 0, nav_dir, &v); + if (FAILED(hr)) + WARN("Child navigation failed with hr %#lx\n", hr); + break;
case NavigateDirection_NextSibling: case NavigateDirection_PreviousSibling:
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 250 ++++++++++----------- dlls/uiautomationcore/uia_client.c | 39 ++++ 2 files changed, 153 insertions(+), 136 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1c6902cc498..827c23e26ef 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -7454,100 +7454,96 @@ static const struct prov_method_sequence nav_seq3[] = {
static const struct prov_method_sequence nav_seq4[] = { { &Provider_hwnd_child2, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ - { &Provider_hwnd_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_hwnd_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS }, /* All Windows versions use the NativeWindowHandle provider type check here. */ { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, - /* Win10v1507 and below call this. */ - { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + NODE_CREATE_SEQ2(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ - { &Provider_nc_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ + { &Provider_nc_child, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider_nc_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, - { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, - { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + { &Provider_nc_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_nc_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + /* Only called on Windows versions past Win10v1507. */ { &Provider_nc_child, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq5[] = { - { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_PreviousSibling */ - { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc_child, FRAG_NAVIGATE }, /* NavigateDirection_PreviousSibling */ + { &Provider_nc_child, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_nc, PROV_GET_PROVIDER_OPTIONS }, { &Provider_nc, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, NODE_CREATE_SEQ2(&Provider), { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_LastChild */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_LastChild */ NODE_CREATE_SEQ(&Provider_hwnd_child2), { &Provider_hwnd_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq6[] = { - { &Provider_nc_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_nc_child, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ NODE_CREATE_SEQ(&Provider_nc_child2), { &Provider_nc_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq7[] = { - { &Provider_nc_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ - { &Provider_nc_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc_child2, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ + { &Provider_nc_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider_nc, PROV_GET_PROVIDER_OPTIONS }, { &Provider_nc, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, NODE_CREATE_SEQ2(&Provider), { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_FirstChild */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ NODE_CREATE_SEQ(&Provider_child), { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq8[] = { - { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ NODE_CREATE_SEQ(&Provider_child2), { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence nav_seq9[] = { - { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_NextSibling */ - { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ @@ -7556,9 +7552,9 @@ static const struct prov_method_sequence nav_seq9[] = { { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done on Win10v1809+ */ { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, - { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ /* Windows 10+ calls these. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -7840,29 +7836,24 @@ static void test_UiaNavigate(void) add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_nc_child", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_nc_child.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child.ref); - todo_wine CHECK_CALLED(prov_callback_nonclient); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); - - node3 = NULL; - if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_nc_child.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child.ref); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - } + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
+ ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); ok_method_sequence(nav_seq4, "nav_seq4");
SafeArrayDestroy(out_req); @@ -7878,66 +7869,60 @@ static void test_UiaNavigate(void) init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_hwnd_child2", TRUE); hr = UiaNavigate(node2, NavigateDirection_PreviousSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_hwnd_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq5, "nav_seq5"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq5, "nav_seq5");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node3), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node3), "UiaNodeRelease returned FALSE\n"); ok(Provider_hwnd_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd_child2.ref);
/* Navigate to Provider_nc_child2. */ init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_nc_child2", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_nc_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child2.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_nc_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_nc_child2.ref);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq6, "nav_seq6"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq6, "nav_seq6");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_nc_child.ref == 1, "Unexpected refcnt %ld\n", Provider_nc_child.ref); node2 = node3;
@@ -7947,34 +7932,31 @@ static void test_UiaNavigate(void) init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); - todo_wine CHECK_CALLED(prov_callback_base_hwnd); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq7, "nav_seq7"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq7, "nav_seq7");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_nc_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_nc_child2.ref); node2 = node3;
@@ -7982,32 +7964,29 @@ static void test_UiaNavigate(void) init_node_provider_desc(&exp_node_desc[0], GetCurrentProcessId(), NULL); add_provider_desc(&exp_node_desc[0], L"Main", L"Provider_child2", TRUE); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok(!!out_req, "out_req == NULL\n"); - todo_wine ok(!!tree_struct, "tree_struct == NULL\n"); - todo_wine ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(!!out_req, "out_req == NULL\n"); + ok(!!tree_struct, "tree_struct == NULL\n"); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref);
- if (out_req) - { - hr = SafeArrayGetElement(out_req, idx, &v); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + hr = SafeArrayGetElement(out_req, idx, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
- hr = UiaHUiaNodeFromVariant(&v, &node3); - ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - IUnknown_AddRef((IUnknown *)node3); + hr = UiaHUiaNodeFromVariant(&v, &node3); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + IUnknown_AddRef((IUnknown *)node3);
- exp_lbound[0] = exp_lbound[1] = 0; - exp_elems[0] = exp_elems[1] = 1; - test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc); + exp_lbound[0] = exp_lbound[1] = 0; + exp_elems[0] = exp_elems[1] = 1; + test_cache_req_sa(out_req, exp_lbound, exp_elems, exp_node_desc);
- ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); - ok_method_sequence(nav_seq8, "nav_seq8"); - } + ok(!wcscmp(tree_struct, L"P)"), "tree structure %s\n", debugstr_w(tree_struct)); + ok_method_sequence(nav_seq8, "nav_seq8");
SafeArrayDestroy(out_req); SysFreeString(tree_struct);
- todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); node2 = node3;
@@ -8016,9 +7995,8 @@ static void test_UiaNavigate(void) SET_EXPECT_MULTI(prov_callback_base_hwnd, 2); SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); hr = UiaNavigate(node2, NavigateDirection_NextSibling, (struct UiaCondition *)&UiaTrueCondition, &cache_req, &out_req, &tree_struct); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - if (SUCCEEDED(hr)) - ok_method_sequence(nav_seq9, "nav_seq9"); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok_method_sequence(nav_seq9, "nav_seq9"); ok(!out_req, "out_req != NULL\n"); ok(!tree_struct, "tree_struct != NULL\n"); todo_wine CHECK_CALLED_MULTI(prov_callback_nonclient, 2); @@ -8027,7 +8005,7 @@ static void test_UiaNavigate(void)
SafeArrayDestroy(out_req); SysFreeString(tree_struct); - todo_wine ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node2), "UiaNodeRelease returned FALSE\n"); ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref);
/* Navigate to Provider_child2, last child. */ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 0c58ef0aca0..dfacebc456f 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -808,10 +808,49 @@ static HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *o
case NavigateDirection_NextSibling: case NavigateDirection_PreviousSibling: + { + struct uia_node *node_data; + HUIANODE parent; + VARIANT tmp; + hr = get_sibling_from_node_provider(node, node->parent_link_idx, nav_dir, &v); if (FAILED(hr)) + { WARN("Sibling navigation failed with hr %#lx\n", hr); + break; + } + + if (V_VT(&v) != VT_EMPTY) + break; + + hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx, + NavigateDirection_Parent, &tmp); + if (FAILED(hr)) + { + WARN("Parent navigation failed with hr %#lx\n", hr); + break; + } + + hr = UiaHUiaNodeFromVariant(&tmp, &parent); + if (FAILED(hr)) + break; + + /* + * If the parent node has multiple providers, attempt to get a sibling + * from one of them. + */ + node_data = impl_from_IWineUiaNode((IWineUiaNode *)parent); + if (node_data->prov_count > 1) + { + if (nav_dir == NavigateDirection_NextSibling) + hr = get_child_for_node(node_data, node_data->creator_prov_idx - 1, NavigateDirection_FirstChild, &v); + else + hr = get_child_for_node(node_data, node_data->creator_prov_idx + 1, NavigateDirection_LastChild, &v); + } + + UiaNodeRelease(parent); break; + }
case NavigateDirection_Parent: hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx, nav_dir, &v);
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=125557
Your paranoid android.
=== debian11 (32 bit report) ===
wmvcore: wmvcore.c:2997: Test failed: Wait timed out.
This merge request was approved by Esme Povirk.