uiautomationcore: Add basic IAccessible2 support.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2022-06-13 13:04:13 -04:00 committed by Alexandre Julliard
parent 7d5708a182
commit 62d76348b3
2 changed files with 656 additions and 0 deletions

View file

@ -24,6 +24,7 @@
#include "initguid.h"
#include "uiautomation.h"
#include "ocidl.h"
#include "wine/iaccessible2.h"
#include "wine/test.h"
@ -73,6 +74,7 @@ DEFINE_EXPECT(Accessible_get_accRole);
DEFINE_EXPECT(Accessible_get_accState);
DEFINE_EXPECT(Accessible_accLocation);
DEFINE_EXPECT(Accessible_get_accChild);
DEFINE_EXPECT(Accessible_get_uniqueID);
DEFINE_EXPECT(Accessible2_get_accParent);
DEFINE_EXPECT(Accessible2_get_accChildCount);
DEFINE_EXPECT(Accessible2_get_accName);
@ -80,6 +82,7 @@ DEFINE_EXPECT(Accessible2_get_accRole);
DEFINE_EXPECT(Accessible2_get_accState);
DEFINE_EXPECT(Accessible2_accLocation);
DEFINE_EXPECT(Accessible2_QI_IAccIdentity);
DEFINE_EXPECT(Accessible2_get_uniqueID);
DEFINE_EXPECT(Accessible_child_accNavigate);
DEFINE_EXPECT(Accessible_child_get_accParent);
DEFINE_EXPECT(Accessible_child_get_accChildCount);
@ -128,7 +131,9 @@ static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2)
static struct Accessible
{
IAccessible IAccessible_iface;
IAccessible2 IAccessible2_iface;
IOleWindow IOleWindow_iface;
IServiceProvider IServiceProvider_iface;
LONG ref;
IAccessible *parent;
@ -139,6 +144,8 @@ static struct Accessible
LONG child_count;
LPCWSTR name;
LONG left, top, width, height;
BOOL enable_ia2;
LONG unique_id;
} Accessible, Accessible2, Accessible_child, Accessible_child2;
static inline struct Accessible* impl_from_Accessible(IAccessible *iface)
@ -164,6 +171,10 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
*obj = iface;
else if (IsEqualIID(riid, &IID_IOleWindow))
*obj = &This->IOleWindow_iface;
else if (IsEqualIID(riid, &IID_IServiceProvider))
*obj = &This->IServiceProvider_iface;
else if (IsEqualIID(riid, &IID_IAccessible2) && This->enable_ia2)
*obj = &This->IAccessible2_iface;
else
return E_NOINTERFACE;
@ -559,6 +570,383 @@ static IAccessibleVtbl AccessibleVtbl = {
Accessible_put_accValue
};
static inline struct Accessible* impl_from_Accessible2(IAccessible2 *iface)
{
return CONTAINING_RECORD(iface, struct Accessible, IAccessible2_iface);
}
static HRESULT WINAPI Accessible2_QueryInterface(IAccessible2 *iface, REFIID riid, void **obj)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_QueryInterface(&This->IAccessible_iface, riid, obj);
}
static ULONG WINAPI Accessible2_AddRef(IAccessible2 *iface)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_AddRef(&This->IAccessible_iface);
}
static ULONG WINAPI Accessible2_Release(IAccessible2 *iface)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_Release(&This->IAccessible_iface);
}
static HRESULT WINAPI Accessible2_GetTypeInfoCount(IAccessible2 *iface, UINT *pctinfo)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_GetTypeInfoCount(&This->IAccessible_iface, pctinfo);
}
static HRESULT WINAPI Accessible2_GetTypeInfo(IAccessible2 *iface, UINT iTInfo,
LCID lcid, ITypeInfo **out_tinfo)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_GetTypeInfo(&This->IAccessible_iface, iTInfo, lcid, out_tinfo);
}
static HRESULT WINAPI Accessible2_GetIDsOfNames(IAccessible2 *iface, REFIID riid,
LPOLESTR *rg_names, UINT name_count, LCID lcid, DISPID *rg_disp_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_GetIDsOfNames(&This->IAccessible_iface, riid, rg_names, name_count,
lcid, rg_disp_id);
}
static HRESULT WINAPI Accessible2_Invoke(IAccessible2 *iface, DISPID disp_id_member,
REFIID riid, LCID lcid, WORD flags, DISPPARAMS *disp_params,
VARIANT *var_result, EXCEPINFO *excep_info, UINT *arg_err)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_Invoke(&This->IAccessible_iface, disp_id_member, riid, lcid, flags,
disp_params, var_result, excep_info, arg_err);
}
static HRESULT WINAPI Accessible2_get_accParent(IAccessible2 *iface, IDispatch **out_parent)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accParent(&This->IAccessible_iface, out_parent);
}
static HRESULT WINAPI Accessible2_get_accChildCount(IAccessible2 *iface, LONG *out_count)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accChildCount(&This->IAccessible_iface, out_count);
}
static HRESULT WINAPI Accessible2_get_accChild(IAccessible2 *iface, VARIANT child_id,
IDispatch **out_child)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accChild(&This->IAccessible_iface, child_id, out_child);
}
static HRESULT WINAPI Accessible2_get_accName(IAccessible2 *iface, VARIANT child_id,
BSTR *out_name)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accName(&This->IAccessible_iface, child_id, out_name);
}
static HRESULT WINAPI Accessible2_get_accValue(IAccessible2 *iface, VARIANT child_id,
BSTR *out_value)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accValue(&This->IAccessible_iface, child_id, out_value);
}
static HRESULT WINAPI Accessible2_get_accDescription(IAccessible2 *iface, VARIANT child_id,
BSTR *out_description)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accDescription(&This->IAccessible_iface, child_id, out_description);
}
static HRESULT WINAPI Accessible2_get_accRole(IAccessible2 *iface, VARIANT child_id,
VARIANT *out_role)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accRole(&This->IAccessible_iface, child_id, out_role);
}
static HRESULT WINAPI Accessible2_get_accState(IAccessible2 *iface, VARIANT child_id,
VARIANT *out_state)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accState(&This->IAccessible_iface, child_id, out_state);
}
static HRESULT WINAPI Accessible2_get_accHelp(IAccessible2 *iface, VARIANT child_id,
BSTR *out_help)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accHelp(&This->IAccessible_iface, child_id, out_help);
}
static HRESULT WINAPI Accessible2_get_accHelpTopic(IAccessible2 *iface,
BSTR *out_help_file, VARIANT child_id, LONG *out_topic_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accHelpTopic(&This->IAccessible_iface, out_help_file, child_id,
out_topic_id);
}
static HRESULT WINAPI Accessible2_get_accKeyboardShortcut(IAccessible2 *iface, VARIANT child_id,
BSTR *out_kbd_shortcut)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accKeyboardShortcut(&This->IAccessible_iface, child_id,
out_kbd_shortcut);
}
static HRESULT WINAPI Accessible2_get_accFocus(IAccessible2 *iface, VARIANT *pchild_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accFocus(&This->IAccessible_iface, pchild_id);
}
static HRESULT WINAPI Accessible2_get_accSelection(IAccessible2 *iface, VARIANT *out_selection)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accSelection(&This->IAccessible_iface, out_selection);
}
static HRESULT WINAPI Accessible2_get_accDefaultAction(IAccessible2 *iface, VARIANT child_id,
BSTR *out_default_action)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_get_accDefaultAction(&This->IAccessible_iface, child_id,
out_default_action);
}
static HRESULT WINAPI Accessible2_accSelect(IAccessible2 *iface, LONG select_flags,
VARIANT child_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_accSelect(&This->IAccessible_iface, select_flags, child_id);
}
static HRESULT WINAPI Accessible2_accLocation(IAccessible2 *iface, LONG *out_left,
LONG *out_top, LONG *out_width, LONG *out_height, VARIANT child_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_accLocation(&This->IAccessible_iface, out_left, out_top, out_width,
out_height, child_id);
}
static HRESULT WINAPI Accessible2_accNavigate(IAccessible2 *iface, LONG nav_direction,
VARIANT child_id_start, VARIANT *out_var)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_accNavigate(&This->IAccessible_iface, nav_direction, child_id_start,
out_var);
}
static HRESULT WINAPI Accessible2_accHitTest(IAccessible2 *iface, LONG left, LONG top,
VARIANT *out_child_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_accHitTest(&This->IAccessible_iface, left, top, out_child_id);
}
static HRESULT WINAPI Accessible2_accDoDefaultAction(IAccessible2 *iface, VARIANT child_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_accDoDefaultAction(&This->IAccessible_iface, child_id);
}
static HRESULT WINAPI Accessible2_put_accName(IAccessible2 *iface, VARIANT child_id,
BSTR name)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_put_accName(&This->IAccessible_iface, child_id, name);
}
static HRESULT WINAPI Accessible2_put_accValue(IAccessible2 *iface, VARIANT child_id,
BSTR value)
{
struct Accessible *This = impl_from_Accessible2(iface);
return IAccessible_put_accValue(&This->IAccessible_iface, child_id, value);
}
static HRESULT WINAPI Accessible2_get_nRelations(IAccessible2 *iface, LONG *out_nRelations)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_relation(IAccessible2 *iface, LONG relation_idx,
IAccessibleRelation **out_relation)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_relations(IAccessible2 *iface, LONG count,
IAccessibleRelation **out_relations, LONG *out_relation_count)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_role(IAccessible2 *iface, LONG *out_role)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_scrollTo(IAccessible2 *iface, enum IA2ScrollType scroll_type)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_scrollToPoint(IAccessible2 *iface,
enum IA2CoordinateType coordinate_type, LONG x, LONG y)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_groupPosition(IAccessible2 *iface, LONG *out_group_level,
LONG *out_similar_items_in_group, LONG *out_position_in_group)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_states(IAccessible2 *iface, AccessibleStates *out_states)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_extendedRole(IAccessible2 *iface, BSTR *out_extended_role)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_localizedExtendedRole(IAccessible2 *iface,
BSTR *out_localized_extended_role)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_nExtendedStates(IAccessible2 *iface, LONG *out_nExtendedStates)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_extendedStates(IAccessible2 *iface, LONG count,
BSTR **out_extended_states, LONG *out_extended_states_count)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_localizedExtendedStates(IAccessible2 *iface, LONG count,
BSTR **out_localized_extended_states, LONG *out_localized_extended_states_count)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_uniqueID(IAccessible2 *iface, LONG *out_unique_id)
{
struct Accessible *This = impl_from_Accessible2(iface);
if (This == &Accessible2)
CHECK_EXPECT(Accessible2_get_uniqueID);
else
CHECK_EXPECT(Accessible_get_uniqueID);
*out_unique_id = 0;
if (This->unique_id)
{
*out_unique_id = This->unique_id;
return S_OK;
}
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_windowHandle(IAccessible2 *iface, HWND *out_hwnd)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_indexInParent(IAccessible2 *iface, LONG *out_idx_in_parent)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_locale(IAccessible2 *iface, IA2Locale *out_locale)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static HRESULT WINAPI Accessible2_get_attributes(IAccessible2 *iface, BSTR *out_attributes)
{
ok(0, "unexpected call\n");
return E_NOTIMPL;
}
static const IAccessible2Vtbl Accessible2Vtbl = {
Accessible2_QueryInterface,
Accessible2_AddRef,
Accessible2_Release,
Accessible2_GetTypeInfoCount,
Accessible2_GetTypeInfo,
Accessible2_GetIDsOfNames,
Accessible2_Invoke,
Accessible2_get_accParent,
Accessible2_get_accChildCount,
Accessible2_get_accChild,
Accessible2_get_accName,
Accessible2_get_accValue,
Accessible2_get_accDescription,
Accessible2_get_accRole,
Accessible2_get_accState,
Accessible2_get_accHelp,
Accessible2_get_accHelpTopic,
Accessible2_get_accKeyboardShortcut,
Accessible2_get_accFocus,
Accessible2_get_accSelection,
Accessible2_get_accDefaultAction,
Accessible2_accSelect,
Accessible2_accLocation,
Accessible2_accNavigate,
Accessible2_accHitTest,
Accessible2_accDoDefaultAction,
Accessible2_put_accName,
Accessible2_put_accValue,
Accessible2_get_nRelations,
Accessible2_get_relation,
Accessible2_get_relations,
Accessible2_role,
Accessible2_scrollTo,
Accessible2_scrollToPoint,
Accessible2_get_groupPosition,
Accessible2_get_states,
Accessible2_get_extendedRole,
Accessible2_get_localizedExtendedRole,
Accessible2_get_nExtendedStates,
Accessible2_get_extendedStates,
Accessible2_get_localizedExtendedStates,
Accessible2_get_uniqueID,
Accessible2_get_windowHandle,
Accessible2_get_indexInParent,
Accessible2_get_locale,
Accessible2_get_attributes,
};
static inline struct Accessible* impl_from_OleWindow(IOleWindow *iface)
{
return CONTAINING_RECORD(iface, struct Accessible, IOleWindow_iface);
@ -603,48 +991,102 @@ static const IOleWindowVtbl OleWindowVtbl = {
OleWindow_ContextSensitiveHelp
};
static inline struct Accessible* impl_from_ServiceProvider(IServiceProvider *iface)
{
return CONTAINING_RECORD(iface, struct Accessible, IServiceProvider_iface);
}
static HRESULT WINAPI ServiceProvider_QueryInterface(IServiceProvider *iface, REFIID riid, void **obj)
{
struct Accessible *This = impl_from_ServiceProvider(iface);
return IAccessible_QueryInterface(&This->IAccessible_iface, riid, obj);
}
static ULONG WINAPI ServiceProvider_AddRef(IServiceProvider *iface)
{
struct Accessible *This = impl_from_ServiceProvider(iface);
return IAccessible_AddRef(&This->IAccessible_iface);
}
static ULONG WINAPI ServiceProvider_Release(IServiceProvider *iface)
{
struct Accessible *This = impl_from_ServiceProvider(iface);
return IAccessible_Release(&This->IAccessible_iface);
}
static HRESULT WINAPI ServiceProvider_QueryService(IServiceProvider *iface, REFGUID service_guid,
REFIID riid, void **obj)
{
struct Accessible *This = impl_from_ServiceProvider(iface);
if (IsEqualIID(riid, &IID_IAccessible2) && IsEqualIID(service_guid, &IID_IAccessible2) &&
This->enable_ia2)
return IAccessible_QueryInterface(&This->IAccessible_iface, riid, obj);
return E_NOTIMPL;
}
static const IServiceProviderVtbl ServiceProviderVtbl = {
ServiceProvider_QueryInterface,
ServiceProvider_AddRef,
ServiceProvider_Release,
ServiceProvider_QueryService,
};
static struct Accessible Accessible =
{
{ &AccessibleVtbl },
{ &Accessible2Vtbl },
{ &OleWindowVtbl },
{ &ServiceProviderVtbl },
1,
NULL,
0, 0,
0, 0, 0, NULL,
0, 0, 0, 0,
FALSE, 0,
};
static struct Accessible Accessible2 =
{
{ &AccessibleVtbl },
{ &Accessible2Vtbl },
{ &OleWindowVtbl },
{ &ServiceProviderVtbl },
1,
NULL,
0, 0,
0, 0, 0, NULL,
0, 0, 0, 0,
FALSE, 0,
};
static struct Accessible Accessible_child =
{
{ &AccessibleVtbl },
{ &Accessible2Vtbl },
{ &OleWindowVtbl },
{ &ServiceProviderVtbl },
1,
&Accessible.IAccessible_iface,
0, 0,
0, 0, 0, NULL,
0, 0, 0, 0,
FALSE, 0,
};
static struct Accessible Accessible_child2 =
{
{ &AccessibleVtbl },
{ &Accessible2Vtbl },
{ &OleWindowVtbl },
{ &ServiceProviderVtbl },
1,
&Accessible.IAccessible_iface,
0, 0,
0, 0, 0, NULL,
0, 0, 0, 0,
FALSE, 0,
};
static IAccessible *acc_client;
@ -1002,6 +1444,166 @@ static void set_accessible_props(struct Accessible *acc, INT role, INT state,
acc->height = height;
}
static void set_accessible_ia2_props(struct Accessible *acc, BOOL enable_ia2, LONG unique_id)
{
acc->enable_ia2 = enable_ia2;
acc->unique_id = unique_id;
}
static void test_uia_prov_from_acc_ia2(void)
{
IRawElementProviderSimple *elprov, *elprov2;
HRESULT hr;
/* Only one exposes an IA2 interface, no match. */
set_accessible_props(&Accessible, 0, 0, 0, L"acc_name", 0, 0, 0, 0);
set_accessible_ia2_props(&Accessible, TRUE, 0);
set_accessible_props(&Accessible2, 0, 0, 0, L"acc_name", 0, 0, 0, 0);
set_accessible_ia2_props(&Accessible2, FALSE, 0);
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (Accessible.ref != 3)
{
IRawElementProviderSimple_Release(elprov);
win_skip("UiaProviderFromIAccessible has no IAccessible2 support, skipping tests.\n");
return;
}
acc_client = &Accessible2.IAccessible_iface;
SET_EXPECT(winproc_GETOBJECT_CLIENT);
elprov2 = (void *)0xdeadbeef;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!elprov2, "elprov != NULL, elprov %p\n", elprov2);
ok(Accessible2.ref == 1, "Unexpected refcnt %ld\n", Accessible2.ref);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
elprov2 = (void *)0xdeadbeef;
acc_client = NULL;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!elprov2, "elprov != NULL, elprov %p\n", elprov2);
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
/*
* If &Accessible returns a failure code on get_uniqueID, &Accessible2's
* uniqueID is not checked.
*/
set_accessible_ia2_props(&Accessible, TRUE, 0);
set_accessible_ia2_props(&Accessible2, TRUE, 0);
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
acc_client = &Accessible2.IAccessible_iface;
SET_EXPECT(winproc_GETOBJECT_CLIENT);
SET_EXPECT(Accessible_get_accRole);
SET_EXPECT(Accessible_get_accState);
SET_EXPECT(Accessible_get_accChildCount);
SET_EXPECT(Accessible_accLocation);
SET_EXPECT(Accessible_get_accName);
SET_EXPECT(Accessible_get_uniqueID);
SET_EXPECT(Accessible2_get_accChildCount);
SET_EXPECT(Accessible2_get_accName);
SET_EXPECT(Accessible2_QI_IAccIdentity);
SET_EXPECT(Accessible2_get_accParent);
elprov2 = (void *)0xdeadbeef;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
ok(Accessible2.ref == 1, "Unexpected refcnt %ld\n", Accessible2.ref);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
CHECK_CALLED(Accessible_get_accRole);
CHECK_CALLED(Accessible_get_accState);
CHECK_CALLED(Accessible_get_accChildCount);
CHECK_CALLED(Accessible_accLocation);
CHECK_CALLED(Accessible_get_accName);
CHECK_CALLED(Accessible_get_uniqueID);
CHECK_CALLED(Accessible2_get_accChildCount);
CHECK_CALLED(Accessible2_get_accName);
todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity);
todo_wine CHECK_CALLED(Accessible2_get_accParent);
IRawElementProviderSimple_Release(elprov2);
elprov2 = (void *)0xdeadbeef;
acc_client = NULL;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
IRawElementProviderSimple_Release(elprov2);
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
/* Unique ID matches. */
set_accessible_ia2_props(&Accessible, TRUE, 1);
set_accessible_ia2_props(&Accessible2, TRUE, 1);
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
acc_client = &Accessible2.IAccessible_iface;
SET_EXPECT(winproc_GETOBJECT_CLIENT);
SET_EXPECT(Accessible_get_uniqueID);
SET_EXPECT(Accessible2_get_uniqueID);
elprov2 = (void *)0xdeadbeef;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
ok(Accessible2.ref == 1, "Unexpected refcnt %ld\n", Accessible2.ref);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
CHECK_CALLED(Accessible_get_uniqueID);
CHECK_CALLED(Accessible2_get_uniqueID);
IRawElementProviderSimple_Release(elprov2);
elprov2 = (void *)0xdeadbeef;
acc_client = NULL;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!!elprov2, "elprov == NULL, elprov %p\n", elprov2);
IRawElementProviderSimple_Release(elprov2);
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
/* Unique ID mismatch. */
set_accessible_ia2_props(&Accessible, TRUE, 1);
set_accessible_ia2_props(&Accessible2, TRUE, 2);
hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(Accessible.ref == 3, "Unexpected refcnt %ld\n", Accessible.ref);
acc_client = &Accessible2.IAccessible_iface;
SET_EXPECT(winproc_GETOBJECT_CLIENT);
SET_EXPECT(Accessible_get_uniqueID);
SET_EXPECT(Accessible2_get_uniqueID);
elprov2 = (void *)0xdeadbeef;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!elprov2, "elprov != NULL, elprov %p\n", elprov2);
ok(Accessible2.ref == 1, "Unexpected refcnt %ld\n", Accessible2.ref);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
CHECK_CALLED(Accessible_get_uniqueID);
CHECK_CALLED(Accessible2_get_uniqueID);
elprov2 = (void *)0xdeadbeef;
acc_client = NULL;
hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
ok(!elprov2, "elprov != NULL, elprov %p\n", elprov2);
IRawElementProviderSimple_Release(elprov);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0);
set_accessible_ia2_props(&Accessible, FALSE, 0);
set_accessible_props(&Accessible2, 0, 0, 0, NULL, 0, 0, 0, 0);
set_accessible_ia2_props(&Accessible2, FALSE, 0);
}
#define check_fragment_acc( fragment, acc, cid) \
check_fragment_acc_( (fragment), (acc), (cid), __LINE__)
static void check_fragment_acc_(IRawElementProviderFragment *elfrag, IAccessible *acc,
@ -2091,6 +2693,7 @@ static void test_UiaProviderFromIAccessible(void)
test_uia_prov_from_acc_properties();
test_uia_prov_from_acc_navigation();
test_uia_prov_from_acc_ia2();
CoUninitialize();
DestroyWindow(hwnd);

View file

@ -24,6 +24,7 @@
#include "wine/debug.h"
#include "wine/heap.h"
#include "initguid.h"
#include "wine/iaccessible2.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
@ -54,6 +55,28 @@ static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
return FALSE;
}
static IAccessible2 *msaa_acc_get_ia2(IAccessible *acc)
{
IServiceProvider *serv_prov;
IAccessible2 *ia2 = NULL;
HRESULT hr;
hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
if (SUCCEEDED(hr))
{
hr = IServiceProvider_QueryService(serv_prov, &IID_IAccessible2, &IID_IAccessible2, (void **)&ia2);
IServiceProvider_Release(serv_prov);
if (SUCCEEDED(hr) && ia2)
return ia2;
}
hr = IAccessible_QueryInterface(acc, &IID_IAccessible2, (void **)&ia2);
if (SUCCEEDED(hr) && ia2)
return ia2;
return NULL;
}
static IAccessible *msaa_acc_da_unwrap(IAccessible *acc)
{
IServiceProvider *sp;
@ -149,8 +172,10 @@ static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2)
static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
{
IAccessible2 *ia2[2] = { NULL, NULL };
IUnknown *unk, *unk2;
BOOL matched = FALSE;
LONG unique_id[2];
BSTR name[2];
VARIANT cid;
HRESULT hr;
@ -165,6 +190,26 @@ static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
goto exit;
}
ia2[0] = msaa_acc_get_ia2(acc);
ia2[1] = msaa_acc_get_ia2(acc2);
if (!ia2[0] != !ia2[1])
goto exit;
if (ia2[0])
{
hr = IAccessible2_get_uniqueID(ia2[0], &unique_id[0]);
if (SUCCEEDED(hr))
{
hr = IAccessible2_get_uniqueID(ia2[1], &unique_id[1]);
if (SUCCEEDED(hr))
{
if (unique_id[0] == unique_id[1])
matched = TRUE;
goto exit;
}
}
}
hr = msaa_acc_prop_match(acc, acc2);
if (FAILED(hr))
goto exit;
@ -201,6 +246,10 @@ exit:
IUnknown_Release(unk2);
IAccessible_Release(acc);
IAccessible_Release(acc2);
if (ia2[0])
IAccessible2_Release(ia2[0]);
if (ia2[1])
IAccessible2_Release(ia2[1]);
return matched;
}
@ -456,6 +505,7 @@ struct msaa_provider {
LONG refcount;
IAccessible *acc;
IAccessible2 *ia2;
VARIANT cid;
HWND hwnd;
LONG control_type;
@ -535,6 +585,8 @@ ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
IAccessible_Release(msaa_prov->acc);
if (msaa_prov->parent)
IAccessible_Release(msaa_prov->parent);
if (msaa_prov->ia2)
IAccessible2_Release(msaa_prov->ia2);
heap_free(msaa_prov);
}
@ -1069,6 +1121,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
variant_init_i4(&msaa_prov->cid, child_id);
msaa_prov->acc = acc;
IAccessible_AddRef(acc);
msaa_prov->ia2 = msaa_acc_get_ia2(acc);
*elprov = &msaa_prov->IRawElementProviderSimple_iface;
return S_OK;