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