Connor McAdams : oleacc: Add support for retrieving an HWND from accNavigate to WindowFromAccessibleObject.

Alexandre Julliard julliard at winehq.org
Tue May 17 15:37:23 CDT 2022


Module: wine
Branch: master
Commit: 92fe1c3cf02148050cf375283087812498cf776a
URL:    https://source.winehq.org/git/wine.git/?a=commit;h=92fe1c3cf02148050cf375283087812498cf776a

Author: Connor McAdams <cmcadams at codeweavers.com>
Date:   Tue May 17 14:38:35 2022 +0200

oleacc: Add support for retrieving an HWND from accNavigate to WindowFromAccessibleObject.

Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
Signed-off-by: Piotr Caban <piotr at codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard at winehq.org>

---

 dlls/oleacc/main.c       |  53 ++++++++++++++++---
 dlls/oleacc/tests/main.c | 129 ++++++++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 173 insertions(+), 9 deletions(-)

diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c
index dced84be7b5..062884f9bf4 100644
--- a/dlls/oleacc/main.c
+++ b/dlls/oleacc/main.c
@@ -30,6 +30,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(oleacc);
 
 static const WCHAR lresult_atom_prefix[] = {'w','i','n','e','_','o','l','e','a','c','c',':'};
 
+#define NAVDIR_INTERNAL_HWND 10
+DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
+
 extern HRESULT WINAPI OLEACC_DllGetClassObject(REFCLSID, REFIID, void**) DECLSPEC_HIDDEN;
 extern BOOL WINAPI OLEACC_DllMain(HINSTANCE, DWORD, void*) DECLSPEC_HIDDEN;
 extern HRESULT WINAPI OLEACC_DllRegisterServer(void) DECLSPEC_HIDDEN;
@@ -400,35 +403,71 @@ HRESULT WINAPI AccessibleObjectFromWindow( HWND hwnd, DWORD dwObjectID,
 
 HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
 {
+    IServiceProvider *sp;
+    IAccessible *acc2;
     IDispatch *parent;
     IOleWindow *ow;
+    VARIANT v, cid;
     HRESULT hres;
 
     TRACE("%p %p\n", acc, phwnd);
 
-    IAccessible_AddRef(acc);
+    hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+    if(SUCCEEDED(hres)) {
+        hres = IOleWindow_GetWindow(ow, phwnd);
+        IOleWindow_Release(ow);
+        if(SUCCEEDED(hres) && *phwnd)
+            return S_OK;
+    }
+
+    VariantInit(&v);
+    variant_init_i4(&cid, CHILDID_SELF);
+    hres = IAccessible_accNavigate(acc, NAVDIR_INTERNAL_HWND, cid, &v);
+    if(SUCCEEDED(hres)) {
+        if(hres == S_OK && V_VT(&v) == VT_I4 && V_I4(&v)) {
+            *phwnd = LongToHandle(V_I4(&v));
+            return S_OK;
+        }
+        /* native leaks v here */
+        VariantClear(&v);
+    }
+
+    hres = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp);
+    if(SUCCEEDED(hres)) {
+        hres = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper,
+                &IID_IAccessible, (void**)&acc2);
+        IServiceProvider_Release(sp);
+    }
+    if(FAILED(hres)) {
+        acc2 = acc;
+        IAccessible_AddRef(acc2);
+    }
+
     while(1) {
-        hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+        hres = IAccessible_QueryInterface(acc2, &IID_IOleWindow, (void**)&ow);
         if(SUCCEEDED(hres)) {
             hres = IOleWindow_GetWindow(ow, phwnd);
             IOleWindow_Release(ow);
-            IAccessible_Release(acc);
-            return hres;
+            if(SUCCEEDED(hres)) {
+                IAccessible_Release(acc2);
+                return hres;
+            }
         }
 
         hres = IAccessible_get_accParent(acc, &parent);
-        IAccessible_Release(acc);
+        IAccessible_Release(acc2);
         if(FAILED(hres))
             return hres;
-        if(hres!=S_OK || !parent) {
+        if(!parent) {
             *phwnd = NULL;
             return hres;
         }
 
-        hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc);
+        hres = IDispatch_QueryInterface(parent, &IID_IAccessible, (void**)&acc2);
         IDispatch_Release(parent);
         if(FAILED(hres))
             return hres;
+        acc = acc2;
     }
 }
 
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c
index 780919c2ab5..a0ab3eb2fb0 100644
--- a/dlls/oleacc/tests/main.c
+++ b/dlls/oleacc/tests/main.c
@@ -59,9 +59,12 @@ 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);
 
+#define NAVDIR_INTERNAL_HWND 10
 DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
 
 static HANDLE (WINAPI *pGetProcessHandleFromHwnd)(HWND);
@@ -93,7 +96,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_hwnd;
+static HWND OleWindow_hwnd;
 
 static HRESULT WINAPI Accessible_QueryInterface(
         IAccessible *iface, REFIID riid, void **ppvObject)
@@ -106,6 +113,12 @@ static HRESULT WINAPI Accessible_QueryInterface(
         return S_OK;
     }
 
+    if(IsEqualIID(riid, &IID_IOleWindow) && (iface == &Accessible)) {
+        *ppvObject = &OleWindow;
+        IOleWindow_AddRef(&OleWindow);
+        return S_OK;
+    }
+
     if(IsEqualIID(riid, &IID_IEnumVARIANT)) {
         CHECK_EXPECT(Accessible_QI_IEnumVARIANT);
         return E_NOINTERFACE;
@@ -157,11 +170,16 @@ static HRESULT WINAPI Accessible_get_accParent(
         IAccessible *iface, IDispatch **ppdispParent)
 {
     if(iface == &Accessible_child)
+    {
         CHECK_EXPECT(Accessible_child_get_accParent);
+        return IAccessible_QueryInterface(&Accessible, &IID_IDispatch,
+                (void **)ppdispParent);
+    }
     else
         CHECK_EXPECT(Accessible_get_accParent);
 
-    return E_NOTIMPL;
+    *ppdispParent = NULL;
+    return S_FALSE;
 }
 
 static HRESULT WINAPI Accessible_get_accChildCount(
@@ -297,7 +315,21 @@ static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *pxLeft,
 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 && Accessible_hwnd) {
+        V_VT(pvarEnd) = VT_I4;
+        V_I4(pvarEnd) = HandleToULong(Accessible_hwnd);
+        return Accessible_hwnd ? S_OK : S_FALSE;
+    }
+
     return E_NOTIMPL;
 }
 
@@ -360,8 +392,47 @@ 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)
+{
+    if(OleWindow_hwnd) {
+        *hwnd = OleWindow_hwnd;
+        return S_OK;
+    }
+    return E_FAIL;
+}
+
+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)
 {
@@ -1844,6 +1915,59 @@ 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_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_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);
+
+    /* Don't return an HWND from either method. */
+    Accessible_hwnd = NULL;
+    OleWindow_hwnd = NULL;
+    hwnd = (HWND)0xdeadbeef;
+    SET_EXPECT(Accessible_accNavigate);
+    SET_EXPECT(Accessible_get_accParent);
+    hr = WindowFromAccessibleObject(&Accessible, &hwnd);
+    /* Return value from IAccessible::get_accParent. */
+    ok(hr == S_FALSE, "got %lx\n", hr);
+    ok(!hwnd, "hwnd %p\n", hwnd);
+    CHECK_CALLED(Accessible_accNavigate);
+    CHECK_CALLED(Accessible_get_accParent);
+
+    /* Successfully retrieve an HWND from a parent IAccessible's IOleWindow interface. */
+    Accessible_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_hwnd = NULL;
+    OleWindow_hwnd = NULL;
+}
+
 START_TEST(main)
 {
     int argc;
@@ -1885,6 +2009,7 @@ START_TEST(main)
     test_AccessibleObjectFromPoint();
     test_CreateStdAccessibleObject_classes();
     test_default_edit_accessible_object();
+    test_WindowFromAccessibleObject();
 
     unregister_window_class();
     CoUninitialize();




More information about the wine-cvs mailing list