[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