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)