From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 38 ++++ dlls/uiautomationcore/uia_com_client.c | 203 ++++++++++++++++++++- 2 files changed, 239 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 2a4f87c7b59..4f4ce10d622 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -11701,6 +11701,43 @@ static void test_Element_Find(IUIAutomation *uia_iface) UnregisterClassA("test_Element_Find class", NULL); }
+static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) +{ + IUIAutomationCondition *cond, *cond2; + IUIAutomationTreeWalker *walker; + HRESULT hr; + + cond = NULL; + hr = IUIAutomation_CreateTrueCondition(uia_iface, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + /* NULL input argument tests. */ + walker = (void *)0xdeadbeef; + hr = IUIAutomation_CreateTreeWalker(uia_iface, NULL, &walker); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!walker, "walker != NULL\n"); + + hr = IUIAutomation_CreateTreeWalker(uia_iface, cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + /* Actually create TreeWalker. */ + walker = NULL; + hr = IUIAutomation_CreateTreeWalker(uia_iface, cond, &walker); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!walker, "walker == NULL\n"); + + hr = IUIAutomationTreeWalker_get_Condition(walker, &cond2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond2, "cond2 == NULL\n"); + + ok(iface_cmp((IUnknown *)cond, (IUnknown *)cond2), "cond != cond2\n"); + IUIAutomationCondition_Release(cond); + IUIAutomationCondition_Release(cond2); + + IUIAutomationTreeWalker_Release(walker); +} + struct uia_com_classes { const GUID *clsid; const GUID *iid; @@ -11802,6 +11839,7 @@ static void test_CUIAutomation(void) test_CUIAutomation_condition_ifaces(uia_iface); test_CUIAutomation_value_conversion(uia_iface); test_CUIAutomation_cache_request_iface(uia_iface); + test_CUIAutomation_TreeWalker_ifaces(uia_iface); test_ElementFromHandle(uia_iface, has_cui8); test_Element_GetPropertyValue(uia_iface); test_Element_cache_methods(uia_iface); diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 4b2e5cba741..ec634be5e13 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -2442,6 +2442,204 @@ exit: return hr; }
+/* + * IUIAutomationTreeWalker interface. + */ +struct uia_tree_walker { + IUIAutomationTreeWalker IUIAutomationTreeWalker_iface; + LONG ref; + + IUIAutomationCondition *nav_cond; + struct UiaCondition *cond_struct; +}; + +static inline struct uia_tree_walker *impl_from_IUIAutomationTreeWalker(IUIAutomationTreeWalker *iface) +{ + return CONTAINING_RECORD(iface, struct uia_tree_walker, IUIAutomationTreeWalker_iface); +} + +static HRESULT WINAPI uia_tree_walker_QueryInterface(IUIAutomationTreeWalker *iface, REFIID riid, void **ppv) +{ + if (IsEqualIID(riid, &IID_IUIAutomationTreeWalker) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomationTreeWalker_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_tree_walker_AddRef(IUIAutomationTreeWalker *iface) +{ + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + ULONG ref = InterlockedIncrement(&tree_walker->ref); + + TRACE("%p, refcount %ld\n", tree_walker, ref); + return ref; +} + +static ULONG WINAPI uia_tree_walker_Release(IUIAutomationTreeWalker *iface) +{ + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + ULONG ref = InterlockedDecrement(&tree_walker->ref); + + TRACE("%p, refcount %ld\n", tree_walker, ref); + if (!ref) + { + IUIAutomationCondition_Release(tree_walker->nav_cond); + heap_free(tree_walker); + } + + return ref; +} + +static HRESULT WINAPI uia_tree_walker_GetParentElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, + IUIAutomationElement **parent) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, parent); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetFirstChildElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, + IUIAutomationElement **first) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, first); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetLastChildElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, + IUIAutomationElement **last) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, last); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetNextSiblingElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, + IUIAutomationElement **next) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, next); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetPreviousSiblingElement(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationElement **prev) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, prev); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_NormalizeElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, + IUIAutomationElement **normalized) +{ + FIXME("%p, %p, %p: stub\n", iface, elem, normalized); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetParentElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **parent) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, parent); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetFirstChildElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **first) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, first); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetLastChildElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **last) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, last); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetNextSiblingElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **next) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, next); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_GetPreviousSiblingElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **prev) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, prev); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_NormalizeElementBuildCache(IUIAutomationTreeWalker *iface, + IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **normalized) +{ + FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, normalized); + return E_NOTIMPL; +} + +static HRESULT WINAPI uia_tree_walker_get_Condition(IUIAutomationTreeWalker *iface, + IUIAutomationCondition **condition) +{ + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p\n", iface, condition); + + if (!condition) + return E_POINTER; + + IUIAutomationCondition_AddRef(tree_walker->nav_cond); + *condition = tree_walker->nav_cond; + + return S_OK; +} + +static const IUIAutomationTreeWalkerVtbl uia_tree_walker_vtbl = { + uia_tree_walker_QueryInterface, + uia_tree_walker_AddRef, + uia_tree_walker_Release, + uia_tree_walker_GetParentElement, + uia_tree_walker_GetFirstChildElement, + uia_tree_walker_GetLastChildElement, + uia_tree_walker_GetNextSiblingElement, + uia_tree_walker_GetPreviousSiblingElement, + uia_tree_walker_NormalizeElement, + uia_tree_walker_GetParentElementBuildCache, + uia_tree_walker_GetFirstChildElementBuildCache, + uia_tree_walker_GetLastChildElementBuildCache, + uia_tree_walker_GetNextSiblingElementBuildCache, + uia_tree_walker_GetPreviousSiblingElementBuildCache, + uia_tree_walker_NormalizeElementBuildCache, + uia_tree_walker_get_Condition, +}; + +static HRESULT create_uia_tree_walker(IUIAutomationTreeWalker **out_tree_walker, IUIAutomationCondition *nav_cond) +{ + struct uia_tree_walker *tree_walker; + struct UiaCondition *cond_struct; + HRESULT hr; + + if (!out_tree_walker) + return E_POINTER; + + *out_tree_walker = NULL; + hr = get_uia_condition_struct_from_iface(nav_cond, &cond_struct); + if (FAILED(hr)) + return hr; + + tree_walker = heap_alloc_zero(sizeof(*tree_walker)); + if (!tree_walker) + return E_OUTOFMEMORY; + + tree_walker->IUIAutomationTreeWalker_iface.lpVtbl = &uia_tree_walker_vtbl; + tree_walker->ref = 1; + tree_walker->nav_cond = nav_cond; + IUIAutomationCondition_AddRef(nav_cond); + tree_walker->cond_struct = cond_struct; + + *out_tree_walker = &tree_walker->IUIAutomationTreeWalker_iface; + return S_OK; +} + /* * IUIAutomation interface. */ @@ -2576,8 +2774,9 @@ static HRESULT WINAPI uia_iface_GetFocusedElementBuildCache(IUIAutomation6 *ifac static HRESULT WINAPI uia_iface_CreateTreeWalker(IUIAutomation6 *iface, IUIAutomationCondition *cond, IUIAutomationTreeWalker **out_walker) { - FIXME("%p, %p, %p: stub\n", iface, cond, out_walker); - return E_NOTIMPL; + TRACE("%p, %p, %p\n", iface, cond, out_walker); + + return create_uia_tree_walker(out_walker, cond); }
static HRESULT WINAPI uia_iface_get_ControlViewWalker(IUIAutomation6 *iface, IUIAutomationTreeWalker **out_walker)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 90 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 68 ++++++++++++++-- 2 files changed, 150 insertions(+), 8 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 4f4ce10d622..de60a0e5a1b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -11701,8 +11701,37 @@ static void test_Element_Find(IUIAutomation *uia_iface) UnregisterClassA("test_Element_Find class", NULL); }
+static const struct prov_method_sequence treewalker_seq1[] = { + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ + NODE_CREATE_SEQ(&Provider_child), + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq2[] = { + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_FirstChild */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq3[] = { + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_LastChild */ + NODE_CREATE_SEQ(&Provider_child2), + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq4[] = { + { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_LastChild */ + NODE_CREATE_SEQ(&Provider_child2), + { &Provider_child2, FRAG_GET_RUNTIME_ID }, + { 0 } +}; + static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) { + HWND hwnd = create_test_hwnd("test_CUIAutomation_TreeWalker_ifaces class"); + IUIAutomationElement *element, *element2; + IUIAutomationCacheRequest *cache_req; IUIAutomationCondition *cond, *cond2; IUIAutomationTreeWalker *walker; HRESULT hr; @@ -11735,7 +11764,68 @@ static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) IUIAutomationCondition_Release(cond); IUIAutomationCondition_Release(cond2);
+ cache_req = NULL; + hr = IUIAutomation_CreateCacheRequest(uia_iface, &cache_req); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cache_req, "cache_req == NULL\n"); + + element = create_test_element_from_hwnd(uia_iface, hwnd, TRUE); + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE); + initialize_provider(&Provider_child2, ProviderOptions_ServerSideProvider, NULL, TRUE); + Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; + provider_add_child(&Provider, &Provider_child); + provider_add_child(&Provider, &Provider_child2); + + /* NavigateDirection_FirstChild. */ + element2 = NULL; + hr = IUIAutomationTreeWalker_GetFirstChildElement(walker, element, &element2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(!!element2, "element2 == NULL\n"); + ok_method_sequence(treewalker_seq1, "treewalker_seq1"); + + IUIAutomationElement_Release(element2); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + + element2 = NULL; + hr = IUIAutomationTreeWalker_GetFirstChildElementBuildCache(walker, element, cache_req, &element2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(!!element2, "element2 == NULL\n"); + ok_method_sequence(treewalker_seq2, "treewalker_seq2"); + + IUIAutomationElement_Release(element2); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + + /* NavigateDirection_LastChild. */ + element2 = NULL; + hr = IUIAutomationTreeWalker_GetLastChildElement(walker, element, &element2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok(!!element2, "element2 == NULL\n"); + ok_method_sequence(treewalker_seq3, "treewalker_seq3"); + + IUIAutomationElement_Release(element2); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + + element2 = NULL; + hr = IUIAutomationTreeWalker_GetLastChildElementBuildCache(walker, element, cache_req, &element2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok(!!element2, "element2 == NULL\n"); + ok_method_sequence(treewalker_seq4, "treewalker_seq4"); + + IUIAutomationElement_Release(element2); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + + IUIAutomationElement_Release(element); + ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref); + + IUIAutomationCacheRequest_Release(cache_req); IUIAutomationTreeWalker_Release(walker); + + DestroyWindow(hwnd); + UnregisterClassA("test_CUIAutomation_TreeWalker_ifaces class", NULL); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index ec634be5e13..0af6b1f1310 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -2449,6 +2449,7 @@ struct uia_tree_walker { IUIAutomationTreeWalker IUIAutomationTreeWalker_iface; LONG ref;
+ IUIAutomationCacheRequest *default_cache_req; IUIAutomationCondition *nav_cond; struct UiaCondition *cond_struct; }; @@ -2486,6 +2487,8 @@ static ULONG WINAPI uia_tree_walker_Release(IUIAutomationTreeWalker *iface) TRACE("%p, refcount %ld\n", tree_walker, ref); if (!ref) { + if (tree_walker->default_cache_req) + IUIAutomationCacheRequest_Release(tree_walker->default_cache_req); IUIAutomationCondition_Release(tree_walker->nav_cond); heap_free(tree_walker); } @@ -2503,15 +2506,21 @@ static HRESULT WINAPI uia_tree_walker_GetParentElement(IUIAutomationTreeWalker * static HRESULT WINAPI uia_tree_walker_GetFirstChildElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationElement **first) { - FIXME("%p, %p, %p: stub\n", iface, elem, first); - return E_NOTIMPL; + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p, %p\n", iface, elem, first); + + return IUIAutomationTreeWalker_GetFirstChildElementBuildCache(iface, elem, tree_walker->default_cache_req, first); }
static HRESULT WINAPI uia_tree_walker_GetLastChildElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationElement **last) { - FIXME("%p, %p, %p: stub\n", iface, elem, last); - return E_NOTIMPL; + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p, %p\n", iface, elem, last); + + return IUIAutomationTreeWalker_GetLastChildElementBuildCache(iface, elem, tree_walker->default_cache_req, last); }
static HRESULT WINAPI uia_tree_walker_GetNextSiblingElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, @@ -2535,6 +2544,40 @@ static HRESULT WINAPI uia_tree_walker_NormalizeElement(IUIAutomationTreeWalker * return E_NOTIMPL; }
+static HRESULT uia_tree_walker_navigate(IUIAutomationTreeWalker *walker, IUIAutomationCacheRequest *cache_req, + IUIAutomationElement *start_elem, int nav_dir, IUIAutomationElement **out_elem) +{ + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(walker); + struct UiaCacheRequest *cache_req_struct; + struct uia_element *element; + BSTR tree_struct = NULL; + SAFEARRAY *sa = NULL; + HRESULT hr; + + if (!out_elem) + return E_POINTER; + + *out_elem = NULL; + if (!start_elem) + return E_POINTER; + + hr = get_uia_cache_request_struct_from_iface(cache_req, &cache_req_struct); + if (FAILED(hr)) + return hr; + + element = impl_from_IUIAutomationElement9((IUIAutomationElement9 *)start_elem); + hr = UiaNavigate(element->node, nav_dir, tree_walker->cond_struct, cache_req_struct, &sa, &tree_struct); + if (SUCCEEDED(hr) && sa) + { + hr = create_uia_element_from_cache_req(out_elem, element->from_cui8, cache_req_struct, 0, sa, tree_struct); + tree_struct = NULL; + } + + SysFreeString(tree_struct); + SafeArrayDestroy(sa); + return hr; +} + static HRESULT WINAPI uia_tree_walker_GetParentElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **parent) { @@ -2545,15 +2588,17 @@ static HRESULT WINAPI uia_tree_walker_GetParentElementBuildCache(IUIAutomationTr static HRESULT WINAPI uia_tree_walker_GetFirstChildElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **first) { - FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, first); - return E_NOTIMPL; + TRACE("%p, %p, %p, %p\n", iface, elem, cache_req, first); + + return uia_tree_walker_navigate(iface, cache_req, elem, NavigateDirection_FirstChild, first); }
static HRESULT WINAPI uia_tree_walker_GetLastChildElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **last) { - FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, last); - return E_NOTIMPL; + TRACE("%p, %p, %p, %p\n", iface, elem, cache_req, last); + + return uia_tree_walker_navigate(iface, cache_req, elem, NavigateDirection_LastChild, last); }
static HRESULT WINAPI uia_tree_walker_GetNextSiblingElementBuildCache(IUIAutomationTreeWalker *iface, @@ -2636,6 +2681,13 @@ static HRESULT create_uia_tree_walker(IUIAutomationTreeWalker **out_tree_walker, IUIAutomationCondition_AddRef(nav_cond); tree_walker->cond_struct = cond_struct;
+ hr = create_uia_cache_request_iface(&tree_walker->default_cache_req); + if (FAILED(hr)) + { + IUIAutomationTreeWalker_Release(&tree_walker->IUIAutomationTreeWalker_iface); + return hr; + } + *out_tree_walker = &tree_walker->IUIAutomationTreeWalker_iface; return S_OK; }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 66 +++++++++++++++++++++- dlls/uiautomationcore/uia_com_client.c | 24 +++++--- 2 files changed, 81 insertions(+), 9 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index de60a0e5a1b..acfcc40bd3b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -11727,10 +11727,36 @@ static const struct prov_method_sequence treewalker_seq4[] = { { 0 } };
+static const struct prov_method_sequence treewalker_seq5[] = { + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_child2), + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq6[] = { + { &Provider_child, FRAG_NAVIGATE }, /* NavigateDirection_NextSibling */ + NODE_CREATE_SEQ(&Provider_child2), + { &Provider_child2, FRAG_GET_RUNTIME_ID }, + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq7[] = { + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_PreviousSibling */ + NODE_CREATE_SEQ(&Provider_child), + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq8[] = { + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_PreviousSibling */ + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_RUNTIME_ID }, + { 0 } +}; + static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) { HWND hwnd = create_test_hwnd("test_CUIAutomation_TreeWalker_ifaces class"); - IUIAutomationElement *element, *element2; + IUIAutomationElement *element, *element2, *element3; IUIAutomationCacheRequest *cache_req; IUIAutomationCondition *cond, *cond2; IUIAutomationTreeWalker *walker; @@ -11794,6 +11820,25 @@ static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) ok(!!element2, "element2 == NULL\n"); ok_method_sequence(treewalker_seq2, "treewalker_seq2");
+ /* NavigateDirection_NextSibling. */ + element3 = NULL; + hr = IUIAutomationTreeWalker_GetNextSiblingElement(walker, element2, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq5, "treewalker_seq5"); + IUIAutomationElement_Release(element3); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + + element3 = NULL; + hr = IUIAutomationTreeWalker_GetNextSiblingElementBuildCache(walker, element2, cache_req, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child2.ref == 2, "Unexpected refcnt %ld\n", Provider_child2.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq6, "treewalker_seq6"); + IUIAutomationElement_Release(element3); + ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref); + IUIAutomationElement_Release(element2); ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref);
@@ -11815,6 +11860,25 @@ static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) ok(!!element2, "element2 == NULL\n"); ok_method_sequence(treewalker_seq4, "treewalker_seq4");
+ /* NavigateDirection_PreviousSibling. */ + element3 = NULL; + hr = IUIAutomationTreeWalker_GetPreviousSiblingElement(walker, element2, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq7, "treewalker_seq7"); + IUIAutomationElement_Release(element3); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + + element3 = NULL; + hr = IUIAutomationTreeWalker_GetPreviousSiblingElementBuildCache(walker, element2, cache_req, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq8, "treewalker_seq8"); + IUIAutomationElement_Release(element3); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + IUIAutomationElement_Release(element2); ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 0af6b1f1310..fa70edb14bf 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -2526,15 +2526,21 @@ static HRESULT WINAPI uia_tree_walker_GetLastChildElement(IUIAutomationTreeWalke static HRESULT WINAPI uia_tree_walker_GetNextSiblingElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationElement **next) { - FIXME("%p, %p, %p: stub\n", iface, elem, next); - return E_NOTIMPL; + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p, %p\n", iface, elem, next); + + return IUIAutomationTreeWalker_GetNextSiblingElementBuildCache(iface, elem, tree_walker->default_cache_req, next); }
static HRESULT WINAPI uia_tree_walker_GetPreviousSiblingElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationElement **prev) { - FIXME("%p, %p, %p: stub\n", iface, elem, prev); - return E_NOTIMPL; + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p, %p\n", iface, elem, prev); + + return IUIAutomationTreeWalker_GetPreviousSiblingElementBuildCache(iface, elem, tree_walker->default_cache_req, prev); }
static HRESULT WINAPI uia_tree_walker_NormalizeElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, @@ -2604,15 +2610,17 @@ static HRESULT WINAPI uia_tree_walker_GetLastChildElementBuildCache(IUIAutomatio static HRESULT WINAPI uia_tree_walker_GetNextSiblingElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **next) { - FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, next); - return E_NOTIMPL; + TRACE("%p, %p, %p, %p\n", iface, elem, cache_req, next); + + return uia_tree_walker_navigate(iface, cache_req, elem, NavigateDirection_NextSibling, next); }
static HRESULT WINAPI uia_tree_walker_GetPreviousSiblingElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **prev) { - FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, prev); - return E_NOTIMPL; + TRACE("%p, %p, %p, %p\n", iface, elem, cache_req, prev); + + return uia_tree_walker_navigate(iface, cache_req, elem, NavigateDirection_PreviousSibling, prev); }
static HRESULT WINAPI uia_tree_walker_NormalizeElementBuildCache(IUIAutomationTreeWalker *iface,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 33 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 12 +++++--- 2 files changed, 41 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index acfcc40bd3b..f1d57336d37 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -11753,6 +11753,19 @@ static const struct prov_method_sequence treewalker_seq8[] = { { 0 } };
+static const struct prov_method_sequence treewalker_seq9[] = { + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider), + { 0 } +}; + +static const struct prov_method_sequence treewalker_seq10[] = { + { &Provider_child2, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ + NODE_CREATE_SEQ(&Provider), + { &Provider, FRAG_GET_RUNTIME_ID }, + { 0 } +}; + static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) { HWND hwnd = create_test_hwnd("test_CUIAutomation_TreeWalker_ifaces class"); @@ -11879,6 +11892,26 @@ static void test_CUIAutomation_TreeWalker_ifaces(IUIAutomation *uia_iface) IUIAutomationElement_Release(element3); ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref);
+ /* NavigateDirection_Parent. */ + element3 = NULL; + Provider.hwnd = NULL; + hr = IUIAutomationTreeWalker_GetParentElement(walker, element2, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq9, "treewalker_seq9"); + IUIAutomationElement_Release(element3); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + + element3 = NULL; + hr = IUIAutomationTreeWalker_GetParentElementBuildCache(walker, element2, cache_req, &element3); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 3, "Unexpected refcnt %ld\n", Provider.ref); + ok(!!element3, "element3 == NULL\n"); + ok_method_sequence(treewalker_seq10, "treewalker_seq10"); + IUIAutomationElement_Release(element3); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + IUIAutomationElement_Release(element2); ok(Provider_child2.ref == 1, "Unexpected refcnt %ld\n", Provider_child2.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index fa70edb14bf..f1c28e81aa8 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -2499,8 +2499,11 @@ static ULONG WINAPI uia_tree_walker_Release(IUIAutomationTreeWalker *iface) static HRESULT WINAPI uia_tree_walker_GetParentElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationElement **parent) { - FIXME("%p, %p, %p: stub\n", iface, elem, parent); - return E_NOTIMPL; + struct uia_tree_walker *tree_walker = impl_from_IUIAutomationTreeWalker(iface); + + TRACE("%p, %p, %p\n", iface, elem, parent); + + return IUIAutomationTreeWalker_GetParentElementBuildCache(iface, elem, tree_walker->default_cache_req, parent); }
static HRESULT WINAPI uia_tree_walker_GetFirstChildElement(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, @@ -2587,8 +2590,9 @@ static HRESULT uia_tree_walker_navigate(IUIAutomationTreeWalker *walker, IUIAuto static HRESULT WINAPI uia_tree_walker_GetParentElementBuildCache(IUIAutomationTreeWalker *iface, IUIAutomationElement *elem, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **parent) { - FIXME("%p, %p, %p, %p: stub\n", iface, elem, cache_req, parent); - return E_NOTIMPL; + TRACE("%p, %p, %p, %p\n", iface, elem, cache_req, parent); + + return uia_tree_walker_navigate(iface, cache_req, elem, NavigateDirection_Parent, parent); }
static HRESULT WINAPI uia_tree_walker_GetFirstChildElementBuildCache(IUIAutomationTreeWalker *iface,
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=130766
Your paranoid android.
=== debian11 (32 bit report) ===
ntoskrnl.exe: driver_pnp.c:727: Test failed: Got 1 remove events.
This merge request was approved by Esme Povirk.
It might be a good idea to have a test for the case where there is no element in the given navigation direction, though I don't think it needs to be duplicated for every method.