[PATCH v2] oleacc: Add support for retrieving an HWND from accNavigate to WindowFromAccessibleObject.
Connor McAdams
cmcadams at codeweavers.com
Wed May 11 15:56:04 CDT 2022
Signed-off-by: Connor McAdams <cmcadams at codeweavers.com>
---
-v2: Fix test failures on 32-bit, make commit subject more clear.
In the prior commit message I wrote about changing behavior around
get_accParent, that was inaccurate. The only difference here is that we
call the accNavigate method only on the initial IAccessible, and not on
any of the IAccessibles returned from get_accParent.
---
dlls/oleacc/main.c | 34 +++++++++--
dlls/oleacc/tests/main.c | 120 ++++++++++++++++++++++++++++++++++++++-
2 files changed, 148 insertions(+), 6 deletions(-)
diff --git a/dlls/oleacc/main.c b/dlls/oleacc/main.c
index dced84be7b5..0add9d9549d 100644
--- a/dlls/oleacc/main.c
+++ b/dlls/oleacc/main.c
@@ -402,20 +402,36 @@ HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
{
IDispatch *parent;
IOleWindow *ow;
+ VARIANT v, cid;
HRESULT hres;
TRACE("%p %p\n", acc, phwnd);
IAccessible_AddRef(acc);
- while(1) {
- hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
- if(SUCCEEDED(hres)) {
- hres = IOleWindow_GetWindow(ow, phwnd);
- IOleWindow_Release(ow);
+
+ ow = NULL;
+ hres = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void**)&ow);
+ if(SUCCEEDED(hres)) {
+ hres = IOleWindow_GetWindow(ow, phwnd);
+ IOleWindow_Release(ow);
+ if(*phwnd) {
IAccessible_Release(acc);
return hres;
}
+ }
+
+ VariantInit(&v);
+ variant_init_i4(&cid, CHILDID_SELF);
+ hres = IAccessible_accNavigate(acc, 10, cid, &v);
+ if(SUCCEEDED(hres) && V_VT(&v) == VT_I4)
+ *phwnd = IntToPtr(V_I4(&v));
+
+ if(ow) {
+ IAccessible_Release(acc);
+ return S_OK;
+ }
+ while(1) {
hres = IAccessible_get_accParent(acc, &parent);
IAccessible_Release(acc);
if(FAILED(hres))
@@ -429,6 +445,14 @@ HRESULT WINAPI WindowFromAccessibleObject(IAccessible *acc, HWND *phwnd)
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);
+ IAccessible_Release(acc);
+ return hres;
+ }
}
}
diff --git a/dlls/oleacc/tests/main.c b/dlls/oleacc/tests/main.c
index 7854764ec08..43dfa039f34 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 = NULL;
+static HWND OleWindow_hwnd = NULL;
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);
@@ -295,7 +312,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 == 10) {
+ V_VT(pvarEnd) = VT_I4;
+ V_I4(pvarEnd) = HandleToULong(Accessible_accnav_hwnd);
+ return S_OK;
+ }
+
return E_NOTIMPL;
}
@@ -358,8 +389,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 +1893,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", hwnd);
+ 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 +1984,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