Signed-off-by: Connor McAdams cmcadams@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();