[PATCH 3/3] uiautomationcore: Implement NavigateDirection_Parent for MSAA Providers.

Connor McAdams wine at gitlab.winehq.org
Sat Jun 11 16:57:54 CDT 2022


From: Connor McAdams <cmcadams at codeweavers.com>

Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
---
 dlls/uiautomationcore/tests/uiautomation.c | 96 ++++++++++------------
 dlls/uiautomationcore/uia_provider.c       | 64 ++++++++++++++-
 2 files changed, 104 insertions(+), 56 deletions(-)

diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index b4958d2dc70..885e520bfd3 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -1078,38 +1078,35 @@ static void test_uia_prov_from_acc_navigation(void)
     elfrag2 = (void *)0xdeadbeef;
     hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
     ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!elfrag2, "elfrag2 != NULL\n");
-    todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
-    todo_wine CHECK_CALLED(Accessible_get_accRole);
-    todo_wine CHECK_CALLED(Accessible_get_accState);
-    todo_wine CHECK_CALLED(Accessible_get_accChildCount);
-    todo_wine CHECK_CALLED(Accessible_accLocation);
-    todo_wine CHECK_CALLED(Accessible_get_accName);
-    todo_wine CHECK_CALLED(Accessible2_get_accRole);
-    todo_wine CHECK_CALLED(Accessible2_get_accState);
-    todo_wine CHECK_CALLED(Accessible2_get_accChildCount);
-    todo_wine CHECK_CALLED(Accessible2_accLocation);
-    todo_wine CHECK_CALLED(Accessible2_get_accName);
+    CHECK_CALLED(winproc_GETOBJECT_CLIENT);
+    CHECK_CALLED(Accessible_get_accRole);
+    CHECK_CALLED(Accessible_get_accState);
+    CHECK_CALLED(Accessible_get_accChildCount);
+    CHECK_CALLED(Accessible_accLocation);
+    CHECK_CALLED(Accessible_get_accName);
+    CHECK_CALLED(Accessible2_get_accRole);
+    CHECK_CALLED(Accessible2_get_accState);
+    CHECK_CALLED(Accessible2_get_accChildCount);
+    CHECK_CALLED(Accessible2_accLocation);
+    CHECK_CALLED(Accessible2_get_accName);
     todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity);
     todo_wine CHECK_CALLED(Accessible2_get_accParent);
     acc_client = NULL;
 
-    if (SUCCEEDED(hr))
-    {
-        /* No check against root IAccessible, since it was done previously. */
-        elprov2 = (void *)0xdeadbeef;
-        hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
-        ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-        ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
-        IRawElementProviderSimple_Release(elprov2);
-    }
+    /* No check against root IAccessible, since it was done previously. */
+    elprov2 = (void *)0xdeadbeef;
+    hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
+    IRawElementProviderSimple_Release(elprov2);
 
     /* Do nothing. */
     elfrag2 = (void *)0xdeadbeef;
     hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
     ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     ok(!elfrag2, "elfrag2 != NULL\n");
 
     elfrag2 = (void *)0xdeadbeef;
@@ -1284,36 +1281,30 @@ static void test_uia_prov_from_acc_navigation(void)
     SET_EXPECT(Accessible2_QI_IAccIdentity);
     SET_EXPECT(Accessible2_get_accParent);
     hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
-    todo_wine ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    todo_wine ok(!!elfrag2, "elfrag2 == NULL\n");
-    todo_wine CHECK_CALLED(Accessible_child_get_accParent);
-    todo_wine CHECK_CALLED(Accessible_child_get_accRole);
-    todo_wine CHECK_CALLED(Accessible2_get_accRole);
+    ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!elfrag2, "elfrag2 == NULL\n");
+    CHECK_CALLED(Accessible_child_get_accParent);
+    CHECK_CALLED(Accessible_child_get_accRole);
+    CHECK_CALLED(Accessible2_get_accRole);
     todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity);
     todo_wine CHECK_CALLED(Accessible2_get_accParent);
-    todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
-    if (elfrag2)
-    {
-        check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
-        IRawElementProviderFragment_Release(elfrag2);
-        ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
-    }
+    CHECK_CALLED(winproc_GETOBJECT_CLIENT);
+    check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
+    IRawElementProviderFragment_Release(elfrag2);
+    ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
     acc_client = NULL;
 
     /* Second call only does get_accParent, no root check. */
     SET_EXPECT(Accessible_child_get_accParent);
     hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
-    todo_wine ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    todo_wine ok(!!elfrag2, "elfrag2 == NULL\n");
-    todo_wine CHECK_CALLED(Accessible_child_get_accParent);
-    if (elfrag2)
-    {
-        check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
-        IRawElementProviderFragment_Release(elfrag2);
-        ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
-    }
+    ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!elfrag2, "elfrag2 == NULL\n");
+    CHECK_CALLED(Accessible_child_get_accParent);
+    check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
+    IRawElementProviderFragment_Release(elfrag2);
+    ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
 
     /* ChildCount of 0, do nothing for First/Last child.*/
     SET_EXPECT(Accessible_child_get_accChildCount);
@@ -1434,15 +1425,12 @@ static void test_uia_prov_from_acc_navigation(void)
      * can't be the root IAccessible.
      */
     hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
-    todo_wine ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
-    todo_wine ok(!!elfrag2, "elfrag2 == NULL\n");
-    if (elfrag2)
-    {
-        check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
-        IRawElementProviderFragment_Release(elfrag2);
-        ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
-    }
+    ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(!!elfrag2, "elfrag2 == NULL\n");
+    check_fragment_acc(elfrag2, &Accessible.IAccessible_iface, CHILDID_SELF);
+    IRawElementProviderFragment_Release(elfrag2);
+    ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref);
 
     /*
      * Test NavigateDirection_First/LastChild on simple child element. Does
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c
index 8701d67a89f..1dfe447331e 100644
--- a/dlls/uiautomationcore/uia_provider.c
+++ b/dlls/uiautomationcore/uia_provider.c
@@ -205,6 +205,21 @@ exit:
     return matched;
 }
 
+static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent)
+{
+    IDispatch *disp = NULL;
+    HRESULT hr;
+
+    *parent = NULL;
+    hr = IAccessible_get_accParent(acc, &disp);
+    if (FAILED(hr) || !disp)
+        return hr;
+
+    hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void**)parent);
+    IDispatch_Release(disp);
+    return hr;
+}
+
 static LONG msaa_role_to_uia_control_type(LONG role)
 {
     switch (role)
@@ -515,9 +530,54 @@ static ULONG WINAPI msaa_fragment_Release(IRawElementProviderFragment *iface)
 static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
         enum NavigateDirection direction, IRawElementProviderFragment **ret_val)
 {
-    FIXME("%p, %d, %p: stub!\n", iface, direction, ret_val);
+    struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
+    IRawElementProviderSimple *elprov;
+    IAccessible *acc;
+    HRESULT hr;
+
+    TRACE("%p, %d, %p\n", iface, direction, ret_val);
+
     *ret_val = NULL;
-    return E_NOTIMPL;
+    switch (direction)
+    {
+    case NavigateDirection_Parent:
+        if (msaa_check_root_acc(msaa_prov))
+            break;
+
+        if (V_I4(&msaa_prov->cid) == CHILDID_SELF)
+        {
+            hr = msaa_acc_get_parent(msaa_prov->acc, &acc);
+            if (FAILED(hr) || !acc)
+                break;
+        }
+        else
+            acc = msaa_prov->acc;
+
+        hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov);
+        if (SUCCEEDED(hr))
+        {
+            struct msaa_provider *prov = impl_from_msaa_provider(elprov);
+            *ret_val = &prov->IRawElementProviderFragment_iface;
+        }
+
+        if (acc != msaa_prov->acc)
+            IAccessible_Release(acc);
+
+        break;
+
+    case NavigateDirection_FirstChild:
+    case NavigateDirection_LastChild:
+    case NavigateDirection_NextSibling:
+    case NavigateDirection_PreviousSibling:
+        FIXME("Unimplemented NavigateDirection %d\n", direction);
+        return E_NOTIMPL;
+
+    default:
+        FIXME("Invalid NavigateDirection %d\n", direction);
+        return E_INVALIDARG;
+    }
+
+    return S_OK;
 }
 
 static HRESULT WINAPI msaa_fragment_GetRuntimeId(IRawElementProviderFragment *iface,
-- 
GitLab

https://gitlab.winehq.org/wine/wine/-/merge_requests/230



More information about the wine-devel mailing list