From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 603 +++++++++++++++++++++ dlls/uiautomationcore/uia_provider.c | 53 ++ 2 files changed, 656 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 15d7b4e784b..2afbeb130dd 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -24,6 +24,7 @@ #include "initguid.h" #include "uiautomation.h" #include "ocidl.h" +#include "ia2/api_all_headers.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); diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 11c8e17b766..1b0abaa9950 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -24,6 +24,7 @@ #include "wine/debug.h" #include "wine/heap.h" #include "initguid.h" +#include "ia2/api_all_headers.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]) && !(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;