[PATCH v3] oleacc: Add support for retrieving an HWND from accNavigate to WindowFromAccessibleObject.

Connor McAdams cmcadams at codeweavers.com
Fri May 13 11:43:55 CDT 2022


Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
---
 dlls/oleacc/main.c       |  51 ++++++++++++++---
 dlls/oleacc/tests/main.c | 121 ++++++++++++++++++++++++++++++++++++++-
 2 files changed, 162 insertions(+), 10 deletions(-)

diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c
index dced84be7b5..1128b6c9b44 100644
--- a/dlls/oleacc/main.c
+++ b/dlls/oleacc/main.c
@@ -398,6 +398,22 @@ HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
     return CreateStdAccessibleObject(hwnd, dwObjectID, riid, ppvObject);
 }
 
+#define NAVDIR_INTERNAL_HWND 10
+static HWND get_hwnd_from_acc_nav(IAccessible *acc)
+{
+    HWND hwnd = NULL;
+    VARIANT v, cid;
+    HRESULT hr;
+
+    VariantInit(&v);
+    variant_init_i4(&cid, CHILDID_SELF);
+    hr = IAccessible_accNavigate(acc, NAVDIR_INTERNAL_HWND, cid, &v);
+    if(SUCCEEDED(hr) && V_VT(&v) == VT_I4)
+        hwnd = IntToPtr(V_I4(&v));
+
+    return hwnd;
+}
+
 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
 {
     IDispatch *parent;
@@ -406,29 +422,46 @@ HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
 
     TRACE("%p %p\n", acc, phwnd);
 
-    IAccessible_AddRef(acc);
-    while(1) {
-        hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+    *phwnd = NULL;
+    hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+    if(SUCCEEDED(hres)) {
+        hres = IOleWindow_GetWindow(ow, phwnd);
+        IOleWindow_Release(ow);
         if(SUCCEEDED(hres)) {
-            hres = IOleWindow_GetWindow(ow, phwnd);
-            IOleWindow_Release(ow);
-            IAccessible_Release(acc);
+            if(!*phwnd)
+                *phwnd = get_hwnd_from_acc_nav(acc);
+
             return hres;
         }
+    }
+
+    *phwnd = get_hwnd_from_acc_nav(acc);
+    if(*phwnd)
+        return S_OK;
 
+    IAccessible_AddRef(acc);
+    while(1) {
         hres = IAccessible_get_accParent(acc, &parent);
         IAccessible_Release(acc);
         if(FAILED(hres))
             return hres;
-        if(hres!=S_OK || !parent) {
-            *phwnd = NULL;
+        if(hres!=S_OK || !parent)
             return hres;
-        }
 
         hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
         IDispatch_Release(parent);
         if(FAILED(hres))
             return hres;
+
+        hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+        if(SUCCEEDED(hres)) {
+            hres = IOleWindow_GetWindow(ow, phwnd);
+            IOleWindow_Release(ow);
+            if(SUCCEEDED(hres)) {
+                IAccessible_Release(acc);
+                return hres;
+            }
+        }
     }
 }
 
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c
index 7854764ec08..70b66d82ca1 100644
--- a/dlls/oleacc/tests/main.c
+++ b/dlls/oleacc/tests/main.c
@@ -59,8 +59,10 @@ DEFINE_EXPECT(Accessible_get_accChildCount);
 DEFINE_EXPECT(Accessible_get_accChild);
 DEFINE_EXPECT(Accessible_get_accName);
 DEFINE_EXPECT(Accessible_get_accParent);
+DEFINE_EXPECT(Accessible_accNavigate);
 DEFINE_EXPECT(Accessible_child_get_accName);
 DEFINE_EXPECT(Accessible_child_get_accParent);
+DEFINE_EXPECT(Accessible_child_accNavigate);
 
 static HANDLE (WINAPI *pGetProcessHandleFromHwnd)(HWND);
 
@@ -91,7 +93,11 @@ static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
     return unk1 == unk2;
 }
 
+static IAccessible Accessible;
 static IAccessible Accessible_child;
+static IOleWindow OleWindow;
+static HWND Accessible_accnav_hwnd;
+static HWND OleWindow_hwnd;
 
 static HRESULT WINAPI Accessible_QueryInterface(
         IAccessible *iface, REFIID riid, void **ppvObject)
@@ -104,6 +110,12 @@ static HRESULT WINAPI Accessible_QueryInterface(
         return S_OK;
     }
 
+    if(IsEqualIID(riid, &IID_IOleWindow) && (iface == &Accessible)) {
+        *ppvObject = &OleWindow;
+        IAccessible_AddRef(iface);
+        return S_OK;
+    }
+
     if(IsEqualIID(riid, &IID_IEnumVARIANT)) {
         CHECK_EXPECT(Accessible_QI_IEnumVARIANT);
         return E_NOINTERFACE;
@@ -155,7 +167,12 @@ static HRESULT WINAPI Accessible_get_accParent(
         IAccessible *iface, IDispatch **ppdispParent)
 {
     if(iface == &Accessible_child)
+    {
         CHECK_EXPECT(Accessible_child_get_accParent);
+        if (OleWindow_hwnd)
+            return IAccessible_QueryInterface(&Accessible, &IID_IDispatch,
+                    (void **)ppdispParent);
+    }
     else
         CHECK_EXPECT(Accessible_get_accParent);
 
@@ -292,10 +309,25 @@ static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *pxLeft,
     return E_NOTIMPL;
 }
 
+#define NAVDIR_INTERNAL_HWND 10
 static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface,
         LONG navDir, VARIANT varStart, VARIANT *pvarEnd)
 {
-    ok(0, "unexpected call\n");
+    if(iface == &Accessible_child)
+        CHECK_EXPECT(Accessible_child_accNavigate);
+    else
+        CHECK_EXPECT(Accessible_accNavigate);
+
+    /*
+     * Magic number value for retrieving an HWND. Used by DynamicAnnotation
+     * IAccessible wrapper.
+     */
+    if(navDir == NAVDIR_INTERNAL_HWND) {
+        V_VT(pvarEnd) = VT_I4;
+        V_I4(pvarEnd) = HandleToULong(Accessible_accnav_hwnd);
+        return S_OK;
+    }
+
     return E_NOTIMPL;
 }
 
@@ -358,8 +390,44 @@ static IAccessibleVtbl AccessibleVtbl = {
     Accessible_put_accValue
 };
 
+static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **obj)
+{
+    return IAccessible_QueryInterface(&Accessible, riid, obj);
+}
+
+static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface)
+{
+    return IAccessible_AddRef(&Accessible);
+}
+
+static ULONG WINAPI OleWindow_Release(IOleWindow *iface)
+{
+    return IAccessible_Release(&Accessible);
+}
+
+static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd)
+{
+    *hwnd = OleWindow_hwnd;
+    return S_OK;
+}
+
+static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL f_enter_mode)
+{
+    ok(0, "unexpected call\n");
+    return E_NOTIMPL;
+}
+
+static const IOleWindowVtbl OleWindowVtbl = {
+    OleWindow_QueryInterface,
+    OleWindow_AddRef,
+    OleWindow_Release,
+    OleWindow_GetWindow,
+    OleWindow_ContextSensitiveHelp
+};
+
 static IAccessible Accessible = {&AccessibleVtbl};
 static IAccessible Accessible_child = {&AccessibleVtbl};
+static IOleWindow OleWindow = {&OleWindowVtbl};
 
 static void test_getroletext(void)
 {
@@ -1826,6 +1894,56 @@ static void test_default_edit_accessible_object(void)
     DestroyWindow(hwnd);
 }
 
+static void test_WindowFromAccessibleObject(void)
+{
+    HRESULT hr;
+    HWND hwnd;
+
+    /* Successfully retrieve an HWND from the IOleWindow interface. */
+    Accessible_accnav_hwnd = NULL;
+    OleWindow_hwnd = (HWND)0xdeadf00d;
+    hwnd = (HWND)0xdeadbeef;
+    hr = WindowFromAccessibleObject(&Accessible, &hwnd);
+    ok(hr == S_OK, "got %lx\n", hr);
+    ok(hwnd == (HWND)0xdeadf00d, "hwnd != 0xdeadf00d!\n");
+
+    /* Successfully retrieve an HWND from IAccessible::accNavigate. */
+    Accessible_accnav_hwnd = (HWND)0xdeadf00d;
+    OleWindow_hwnd = NULL;
+    hwnd = (HWND)0xdeadbeef;
+    SET_EXPECT(Accessible_accNavigate);
+    hr = WindowFromAccessibleObject(&Accessible, &hwnd);
+    ok(hr == S_OK, "got %lx\n", hr);
+    /* This value gets sign-extended on 64-bit. */
+    ok(hwnd == IntToPtr(0xdeadf00d), "hwnd != 0xdeadf00d!\n");
+    CHECK_CALLED(Accessible_accNavigate);
+
+    /* Return a NULL HWND from both methods, no accParent call. */
+    Accessible_accnav_hwnd = NULL;
+    OleWindow_hwnd = NULL;
+    hwnd = (HWND)0xdeadbeef;
+    SET_EXPECT(Accessible_accNavigate);
+    hr = WindowFromAccessibleObject(&Accessible, &hwnd);
+    ok(hr == S_OK, "got %lx\n", hr);
+    ok(!hwnd, "hwnd %p\n", hwnd);
+    CHECK_CALLED(Accessible_accNavigate);
+
+    /* Successfully retrieve an HWND from a parent IAccessible's IOleWindow interface. */
+    Accessible_accnav_hwnd = NULL;
+    OleWindow_hwnd = (HWND)0xdeadf00d;
+    hwnd = (HWND)0xdeadbeef;
+    SET_EXPECT(Accessible_child_accNavigate);
+    SET_EXPECT(Accessible_child_get_accParent);
+    hr = WindowFromAccessibleObject(&Accessible_child, &hwnd);
+    ok(hr == S_OK, "got %lx\n", hr);
+    ok(hwnd == (HWND)0xdeadf00d, "hwnd != 0xdeadf00d!\n");
+    CHECK_CALLED(Accessible_child_accNavigate);
+    CHECK_CALLED(Accessible_child_get_accParent);
+
+    Accessible_accnav_hwnd = NULL;
+    OleWindow_hwnd = NULL;
+}
+
 START_TEST(main)
 {
     int argc;
@@ -1867,6 +1985,7 @@ START_TEST(main)
     test_AccessibleObjectFromPoint();
     test_CreateStdAccessibleObject_classes();
     test_default_edit_accessible_object();
+    test_WindowFromAccessibleObject();
 
     unregister_window_class();
     CoUninitialize();
-- 
2.25.1




More information about the wine-devel mailing list