-- v3: uiautomationcore: Add ILegacyIAccessibleProvider implementation for MSAA providers. include: Add ILegacyIAccessibleProvider interface definition. uiautomationcore: Implement get_HostRawElementProvider for MSAA providers.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 479 ++++++++++++++++++++- dlls/uiautomationcore/uia_provider.c | 190 +++++++- 2 files changed, 654 insertions(+), 15 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index f3e4b89a120..6ed3c907a40 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -58,13 +58,21 @@ static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD, DEFINE_EXPECT(winproc_GETOBJECT_CLIENT); DEFINE_EXPECT(Accessible_accNavigate); DEFINE_EXPECT(Accessible_get_accParent); +DEFINE_EXPECT(Accessible_get_accChildCount); +DEFINE_EXPECT(Accessible_get_accName); DEFINE_EXPECT(Accessible_get_accRole); DEFINE_EXPECT(Accessible_get_accState); +DEFINE_EXPECT(Accessible_accLocation); +DEFINE_EXPECT(Accessible2_get_accParent); +DEFINE_EXPECT(Accessible2_get_accChildCount); +DEFINE_EXPECT(Accessible2_get_accName); +DEFINE_EXPECT(Accessible2_get_accRole); +DEFINE_EXPECT(Accessible2_get_accState); +DEFINE_EXPECT(Accessible2_accLocation); +DEFINE_EXPECT(Accessible2_QI_IAccIdentity); DEFINE_EXPECT(Accessible_child_accNavigate); DEFINE_EXPECT(Accessible_child_get_accParent);
-static IAccessible *acc_client; - static BOOL check_variant_i4(VARIANT *v, int val) { if (V_VT(v) == VT_I4 && V_I4(v) == val) @@ -92,7 +100,10 @@ static struct Accessible HWND ow_hwnd; INT role; INT state; -} Accessible, Accessible_child; + LONG child_count; + LPCWSTR name; + LONG left, top, width, height; +} Accessible, Accessible2, Accessible_child;
static inline struct Accessible* impl_from_Accessible(IAccessible *iface) { @@ -104,6 +115,14 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid, struct Accessible *This = impl_from_Accessible(iface);
*obj = NULL; + if (IsEqualIID(riid, &IID_IAccIdentity)) + { + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_QI_IAccIdentity); + ok(This == &Accessible2, "unexpected call\n"); + return E_NOINTERFACE; + } + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) || IsEqualIID(riid, &IID_IAccessible)) *obj = iface; @@ -162,6 +181,8 @@ static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **o
if (This == &Accessible_child) CHECK_EXPECT(Accessible_child_get_accParent); + else if (This == &Accessible2) + CHECK_EXPECT(Accessible2_get_accParent); else CHECK_EXPECT(Accessible_get_accParent);
@@ -174,7 +195,19 @@ static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **o
static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *out_count) { - ok(0, "unexpected call\n"); + struct Accessible *This = impl_from_Accessible(iface); + + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_get_accChildCount); + else + CHECK_EXPECT(Accessible_get_accChildCount); + + if (This->child_count) + { + *out_count = This->child_count; + return S_OK; + } + return E_NOTIMPL; }
@@ -188,7 +221,20 @@ static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT child_ static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT child_id, BSTR *out_name) { - ok(0, "unexpected call\n"); + struct Accessible *This = impl_from_Accessible(iface); + + *out_name = NULL; + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_get_accName); + else + CHECK_EXPECT(Accessible_get_accName); + + if (This->name) + { + *out_name = SysAllocString(This->name); + return S_OK; + } + return E_NOTIMPL; }
@@ -211,8 +257,10 @@ static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT child_i { struct Accessible *This = impl_from_Accessible(iface);
- ok(This == &Accessible, "unexpected call\n"); - CHECK_EXPECT(Accessible_get_accRole); + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_get_accRole); + else + CHECK_EXPECT(Accessible_get_accRole);
if (This->role) { @@ -229,8 +277,10 @@ static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT child_ { struct Accessible *This = impl_from_Accessible(iface);
- ok(This == &Accessible, "unexpected call\n"); - CHECK_EXPECT(Accessible_get_accState); + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_get_accState); + else + CHECK_EXPECT(Accessible_get_accState);
if (This->state) { @@ -292,7 +342,22 @@ static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG select_flags static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left, LONG *out_top, LONG *out_width, LONG *out_height, VARIANT child_id) { - ok(0, "unexpected call\n"); + struct Accessible *This = impl_from_Accessible(iface); + + if (This == &Accessible2) + CHECK_EXPECT(Accessible2_accLocation); + else + CHECK_EXPECT(Accessible_accLocation); + + if (This->width && This->height) + { + *out_left = This->left; + *out_top = This->top; + *out_width = This->width; + *out_height = This->height; + return S_OK; + } + return E_NOTIMPL; }
@@ -430,8 +495,21 @@ static struct Accessible Accessible = 1, NULL, 0, 0, + 0, 0, 0, NULL, + 0, 0, 0, 0, +}; + +static struct Accessible Accessible2 = +{ + { &AccessibleVtbl }, + { &OleWindowVtbl }, + 1, + NULL, 0, 0, + 0, 0, 0, NULL, + 0, 0, 0, 0, }; + static struct Accessible Accessible_child = { { &AccessibleVtbl }, @@ -439,9 +517,11 @@ static struct Accessible Accessible_child = 1, &Accessible.IAccessible_iface, 0, 0, - 0, 0, + 0, 0, 0, NULL, + 0, 0, 0, 0, };
+static IAccessible *acc_client; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) @@ -782,6 +862,20 @@ static const struct msaa_state_uia_prop msaa_state_uia_props[] = { { STATE_SYSTEM_PROTECTED, UIA_IsPasswordPropertyId }, };
+static void set_accessible_props(struct Accessible *acc, INT role, INT state, + LONG child_count, LPCWSTR name, LONG left, LONG top, LONG width, LONG height) +{ + + acc->role = role; + acc->state = state; + acc->child_count = child_count; + acc->name = name; + acc->left = left; + acc->top = top; + acc->width = width; + acc->height = height; +} + static void test_uia_prov_from_acc_properties(void) { IRawElementProviderSimple *elprov; @@ -883,7 +977,7 @@ static void test_uia_prov_from_acc_properties(void)
static void test_UiaProviderFromIAccessible(void) { - IRawElementProviderSimple *elprov; + IRawElementProviderSimple *elprov, *elprov2; enum ProviderOptions prov_opt; IAccessible *acc; WNDCLASSA cls; @@ -891,7 +985,7 @@ static void test_UiaProviderFromIAccessible(void) HWND hwnd; VARIANT v;
- + CoInitializeEx(NULL, COINIT_MULTITHREADED); cls.style = 0; cls.lpfnWndProc = test_wnd_proc; cls.cbClsExtra = 0; @@ -997,11 +1091,370 @@ static void test_UiaProviderFromIAccessible(void) hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, 1, UIA_PFIA_DEFAULT, &elprov); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + /* + * Simple child element (IAccessible without CHILDID_SELF) cannot be root + * IAccessible. No checks against the root HWND IAccessible will be done. + */ + elprov2 = (void *)0xdeadbeef; + hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!elprov2, "elprov != NULL\n"); + + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* + * &Accessible.IAccessible_iface will be compared against the default + * client accessible object. Since we have all properties set to 0, + * we return failure HRESULTs and all properties will get queried but not + * compared. + */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + 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); + elprov2 = (void *)0xdeadbeef; + hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!elprov2, "elprov != NULL\n"); + 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); + + /* Second call won't send WM_GETOBJECT. */ + elprov2 = (void *)0xdeadbeef; + hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &elprov2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!elprov2, "elprov != NULL\n"); + + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* + * Return &Accessible.IAccessible_iface in response to OBJID_CLIENT, + * interface pointers will be compared, no method calls to check property + * values. + */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + SET_EXPECT(winproc_GETOBJECT_CLIENT); + elprov2 = (void *)0xdeadbeef; + acc_client = &Accessible.IAccessible_iface; + 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); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + + /* Second call, no checks. */ + 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); + + /* + * Return &Accessible2.IAccessible_iface in response to OBJID_CLIENT, + * interface pointers won't match, so properties will be compared. + */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, + L"acc_name", 0, 0, 50, 50); + set_accessible_props(&Accessible2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, + L"acc_name", 0, 0, 50, 50); + + 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(Accessible2_get_accRole); + SET_EXPECT(Accessible2_get_accState); + SET_EXPECT(Accessible2_get_accChildCount); + SET_EXPECT(Accessible2_accLocation); + SET_EXPECT(Accessible2_get_accName); + /* + * The IAccessible returned by WM_GETOBJECT will be checked for an + * IAccIdentity interface to see if Dynamic Annotation properties should + * be queried. If not present on the current IAccessible, it will check + * the parent IAccessible for one. + */ + 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(Accessible2_get_accRole); + CHECK_CALLED(Accessible2_get_accState); + CHECK_CALLED(Accessible2_get_accChildCount); + CHECK_CALLED(Accessible2_accLocation); + 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); + + /* + * If a failure HRESULT is returned from the IRawElementProviderSimple + * IAccessible, the corresponding AOFW IAccessible method isn't called. + * An exception is get_accChildCount, which is always called, but only + * checked if the HRESULT return value is not a failure. If Role/State/Name + * are not queried, no IAccIdentity check is done. + */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0); + set_accessible_props(&Accessible2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, + L"acc_name", 0, 0, 50, 50); + + 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(Accessible2_get_accChildCount); + SET_EXPECT(Accessible_accLocation); + SET_EXPECT(Accessible_get_accName); + 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); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(Accessible_get_accRole); + CHECK_CALLED(Accessible_get_accState); + CHECK_CALLED(Accessible_get_accChildCount); + CHECK_CALLED(Accessible2_get_accChildCount); + CHECK_CALLED(Accessible_accLocation); + CHECK_CALLED(Accessible_get_accName); + + acc_client = NULL; + 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); + + IRawElementProviderSimple_Release(elprov); + ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref); + + /* + * Properties are checked in a sequence of accRole, accState, + * accChildCount, accLocation, and finally accName. If a mismatch is found + * early in the sequence, the rest aren't checked. + */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 0, NULL, 0, 0, 0, 0); + set_accessible_props(&Accessible2, ROLE_SYSTEM_CLIENT, STATE_SYSTEM_FOCUSABLE, 0, NULL, 0, 0, 0, 0); + + acc_client = &Accessible2.IAccessible_iface; + SET_EXPECT(winproc_GETOBJECT_CLIENT); + SET_EXPECT(Accessible_get_accRole); + SET_EXPECT(Accessible2_get_accRole); + 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); + CHECK_CALLED(winproc_GETOBJECT_CLIENT); + CHECK_CALLED(Accessible_get_accRole); + CHECK_CALLED(Accessible2_get_accRole); + todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity); + todo_wine CHECK_CALLED(Accessible2_get_accParent); + + 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); + + /* 4/5 properties match, considered a match. */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, NULL, 0, 0, 50, 50); + set_accessible_props(&Accessible2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, NULL, 0, 0, 50, 50); + + 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(Accessible2_get_accRole); + SET_EXPECT(Accessible2_get_accState); + SET_EXPECT(Accessible2_get_accChildCount); + SET_EXPECT(Accessible2_accLocation); + 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(Accessible2_get_accRole); + CHECK_CALLED(Accessible2_get_accState); + CHECK_CALLED(Accessible2_get_accChildCount); + CHECK_CALLED(Accessible2_accLocation); + 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); + + /* 3/5 properties match, not considered a match. */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, NULL, 0, 0, 0, 0); + set_accessible_props(&Accessible2, ROLE_SYSTEM_DOCUMENT, STATE_SYSTEM_FOCUSABLE, 1, NULL, 0, 0, 0, 0); + + 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(Accessible2_get_accRole); + SET_EXPECT(Accessible2_get_accState); + SET_EXPECT(Accessible2_get_accChildCount); + 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); + 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(Accessible2_get_accRole); + CHECK_CALLED(Accessible2_get_accState); + CHECK_CALLED(Accessible2_get_accChildCount); + todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity); + todo_wine CHECK_CALLED(Accessible2_get_accParent); + + 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); + + /* Only name matches, considered a match. */ + hr = pUiaProviderFromIAccessible(&Accessible.IAccessible_iface, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible.ref == 2, "Unexpected refcnt %ld\n", Accessible.ref); + + set_accessible_props(&Accessible, 0, 0, 0, L"acc_name", 0, 0, 0, 0); + set_accessible_props(&Accessible2, 0, 0, 0, L"acc_name", 0, 0, 0, 0); + + 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(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(Accessible2_get_accChildCount); + CHECK_CALLED(Accessible2_get_accName); + todo_wine CHECK_CALLED(Accessible2_QI_IAccIdentity); + todo_wine CHECK_CALLED(Accessible2_get_accParent); + + 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);
test_uia_prov_from_acc_properties();
+ CoUninitialize(); DestroyWindow(hwnd); UnregisterClassA("pUiaProviderFromIAccessible class", NULL); Accessible.acc_hwnd = NULL; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index dae0187596d..6c3bd1c2186 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -23,9 +23,12 @@
#include "wine/debug.h" #include "wine/heap.h" +#include "initguid.h"
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76); + static void variant_init_i4(VARIANT *v, int val) { V_VT(v) = VT_I4; @@ -51,6 +54,157 @@ static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag) return FALSE; }
+static IAccessible *msaa_acc_da_unwrap(IAccessible *acc) +{ + IServiceProvider *sp; + IAccessible *acc2; + HRESULT hr; + + hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp); + if (SUCCEEDED(hr)) + { + hr = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper, &IID_IAccessible, (void**)&acc2); + IServiceProvider_Release(sp); + } + + if (SUCCEEDED(hr) && acc2) + return acc2; + + IAccessible_AddRef(acc); + return acc; +} + +/* + * Compare role, state, child count, and location properties of the two + * IAccessibles. If all four are successfully retrieved and are equal, this is + * considered a match. + */ +static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2) +{ + BOOL role_match, state_match, child_count_match, location_match; + LONG child_count[2], left[2], top[2], width[2], height[2]; + VARIANT cid, v, v2; + HRESULT hr, hr2; + + role_match = state_match = child_count_match = location_match = FALSE; + variant_init_i4(&cid, CHILDID_SELF); + hr = IAccessible_get_accRole(acc, cid, &v); + if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4)) + { + VariantInit(&v2); + hr = IAccessible_get_accRole(acc2, cid, &v2); + if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4)) + { + if (V_I4(&v) != V_I4(&v2)) + return E_FAIL; + + role_match = TRUE; + } + } + + VariantInit(&v); + hr = IAccessible_get_accState(acc, cid, &v); + if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4)) + { + VariantInit(&v2); + hr = IAccessible_get_accState(acc2, cid, &v2); + if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4)) + { + if (V_I4(&v) != V_I4(&v2)) + return E_FAIL; + + state_match = TRUE; + } + } + + hr = IAccessible_get_accChildCount(acc, &child_count[0]); + hr2 = IAccessible_get_accChildCount(acc2, &child_count[1]); + if (SUCCEEDED(hr) && SUCCEEDED(hr2)) + { + if (child_count[0] != child_count[1]) + return E_FAIL; + + child_count_match = TRUE; + } + + hr = IAccessible_accLocation(acc, &left[0], &top[0], &width[0], &height[0], cid); + if (SUCCEEDED(hr)) + { + hr = IAccessible_accLocation(acc2, &left[1], &top[1], &width[1], &height[1], cid); + if (SUCCEEDED(hr)) + { + if ((left[0] != left[1]) || (top[0] != top[1]) || (width[0] != width[1]) || + (height[0] != height[1])) + return E_FAIL; + + location_match = TRUE; + } + } + + if (role_match && state_match && child_count_match && location_match) + return S_OK; + + return S_FALSE; +} + +static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2) +{ + IUnknown *unk, *unk2; + BOOL matched = FALSE; + BSTR name[2]; + VARIANT cid; + HRESULT hr; + + acc = msaa_acc_da_unwrap(acc); + acc2 = msaa_acc_da_unwrap(acc2); + IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk); + IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2); + if (unk == unk2) + { + matched = TRUE; + goto exit; + } + + hr = msaa_acc_prop_match(acc, acc2); + if (FAILED(hr)) + goto exit; + if (hr == S_OK) + matched = TRUE; + + variant_init_i4(&cid, CHILDID_SELF); + hr = IAccessible_get_accName(acc, cid, &name[0]); + if (SUCCEEDED(hr)) + { + hr = IAccessible_get_accName(acc2, cid, &name[1]); + if (SUCCEEDED(hr)) + { + if (!name[0] && !name[1]) + matched = TRUE; + else if (!name[0] || !name[1]) + matched = FALSE; + else + { + if (!wcscmp(name[0], name[1])) + matched = TRUE; + else + matched = FALSE; + } + + SysFreeString(name[1]); + } + + SysFreeString(name[0]); + } + +exit: + IUnknown_Release(unk); + IUnknown_Release(unk2); + IAccessible_Release(acc); + IAccessible_Release(acc2); + + return matched; +} + static LONG msaa_role_to_uia_control_type(LONG role) { switch (role) @@ -141,8 +295,34 @@ struct msaa_provider { VARIANT cid; HWND hwnd; LONG control_type; + + BOOL root_acc_check_ran; + BOOL is_root_acc; };
+static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov) +{ + IAccessible *acc; + HRESULT hr; + + if (msaa_prov->root_acc_check_ran) + return msaa_prov->is_root_acc; + + msaa_prov->root_acc_check_ran = TRUE; + if (V_I4(&msaa_prov->cid) != CHILDID_SELF) + return FALSE; + + hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc); + if (FAILED(hr)) + return FALSE; + + if (msaa_acc_compare(msaa_prov->acc, acc)) + msaa_prov->is_root_acc = TRUE; + + IAccessible_Release(acc); + return msaa_prov->is_root_acc; +} + static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface) { return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface); @@ -264,9 +444,15 @@ HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface, HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface, IRawElementProviderSimple **ret_val) { - FIXME("%p, %p: stub!\n", iface, ret_val); + struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface); + + TRACE("%p, %p\n", iface, ret_val); + *ret_val = NULL; - return E_NOTIMPL; + if (msaa_check_root_acc(msaa_prov)) + return UiaHostProviderFromHwnd(msaa_prov->hwnd, ret_val); + + return S_OK; }
static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- include/uiautomationcore.idl | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+)
diff --git a/include/uiautomationcore.idl b/include/uiautomationcore.idl index 170b0c76de1..c4aa258b5af 100644 --- a/include/uiautomationcore.idl +++ b/include/uiautomationcore.idl @@ -151,4 +151,35 @@ library UIA
HRESULT GetFocus([out, retval] IRawElementProviderFragment **pRetVal); } + + [ + object, + uuid(e44c3566-915d-4070-99c6-047bff5a08f5), + pointer_default(unique), + oleautomation + ] + interface ILegacyIAccessibleProvider : IUnknown + { + HRESULT Select(long flagsSelect); + HRESULT DoDefaultAction(); + HRESULT SetValue(LPCWSTR szValue); + HRESULT GetIAccessible([out, retval] IAccessible **ppAccessible); + + [propget] HRESULT ChildId([out, retval] int *pRetVal); + [propget] HRESULT Name([out, retval] BSTR *pszName); + [propget] HRESULT Value([out, retval] BSTR *pszValue); + [propget] HRESULT Description([out, retval] BSTR *pszDescription); + [propget] HRESULT Role([out, retval] DWORD *pdwRole); + [propget] HRESULT State([out, retval] DWORD *pdwState); + [propget] HRESULT Help([out, retval] BSTR *pszHelp); + [propget] HRESULT KeyboardShortcut([out, retval] BSTR *pszKeyboardShortcut); + /* + * FIXME: Current versions of Windows SDK use + * SAFEARRAY(IRawElementProviderSimple *) instead of + * SAFEARRAY(VARIANT). The new type is currently unsupported + * in widl, we should switch to it when it is. + */ + HRESULT GetSelection([out, retval] SAFEARRAY(VARIANT) *pvarSelectedChildren); + [propget] HRESULT DefaultAction([out, retval] BSTR *pszDefaultAction); + } }
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 57 +++++++ dlls/uiautomationcore/uia_provider.c | 167 ++++++++++++++++++++- 2 files changed, 222 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 6ed3c907a40..6c07edcffa8 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -89,6 +89,20 @@ static BOOL check_variant_bool(VARIANT *v, BOOL val) return FALSE; }
+static BOOL iface_cmp(IUnknown *iface1, IUnknown *iface2) +{ + IUnknown *unk1, *unk2; + BOOL cmp; + + IUnknown_QueryInterface(iface1, &IID_IUnknown, (void**)&unk1); + IUnknown_QueryInterface(iface2, &IID_IUnknown, (void**)&unk2); + cmp = (unk1 == unk2) ? TRUE : FALSE; + + IUnknown_Release(unk1); + IUnknown_Release(unk2); + return cmp; +} + static struct Accessible { IAccessible IAccessible_iface; @@ -977,13 +991,16 @@ static void test_uia_prov_from_acc_properties(void)
static void test_UiaProviderFromIAccessible(void) { + ILegacyIAccessibleProvider *accprov; IRawElementProviderSimple *elprov, *elprov2; enum ProviderOptions prov_opt; IAccessible *acc; + IUnknown *unk; WNDCLASSA cls; HRESULT hr; HWND hwnd; VARIANT v; + INT cid;
CoInitializeEx(NULL, COINIT_MULTITHREADED); cls.style = 0; @@ -1084,6 +1101,26 @@ static void test_UiaProviderFromIAccessible(void) ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); VariantClear(&v);
+ hr = IRawElementProviderSimple_GetPatternProvider(elprov, UIA_LegacyIAccessiblePatternId, &unk); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!unk, "unk == NULL\n"); + ok(iface_cmp((IUnknown *)elprov, unk), "unk != elprov\n"); + + hr = IUnknown_QueryInterface(unk, &IID_ILegacyIAccessibleProvider, (void **)&accprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!accprov, "accprov == NULL\n"); + + hr = ILegacyIAccessibleProvider_get_ChildId(accprov, &cid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(cid == CHILDID_SELF, "cid != CHILDID_SELF\n"); + + hr = ILegacyIAccessibleProvider_GetIAccessible(accprov, &acc); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(acc == &Accessible.IAccessible_iface, "acc != &Accessible.IAccessible_iface\n"); + IAccessible_Release(acc); + IUnknown_Release(unk); + ILegacyIAccessibleProvider_Release(accprov); + IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
@@ -1101,6 +1138,26 @@ static void test_UiaProviderFromIAccessible(void) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!elprov2, "elprov != NULL\n");
+ hr = IRawElementProviderSimple_GetPatternProvider(elprov, UIA_LegacyIAccessiblePatternId, &unk); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!unk, "unk == NULL\n"); + ok(iface_cmp((IUnknown *)elprov, unk), "unk != elprov\n"); + + hr = IUnknown_QueryInterface(unk, &IID_ILegacyIAccessibleProvider, (void **)&accprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!accprov, "accprov == NULL\n"); + + hr = ILegacyIAccessibleProvider_get_ChildId(accprov, &cid); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(cid == 1, "cid != CHILDID_SELF\n"); + + hr = ILegacyIAccessibleProvider_GetIAccessible(accprov, &acc); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(acc == &Accessible.IAccessible_iface, "acc != &Accessible.IAccessible_iface\n"); + IAccessible_Release(acc); + IUnknown_Release(unk); + ILegacyIAccessibleProvider_Release(accprov); + IRawElementProviderSimple_Release(elprov); ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 6c3bd1c2186..9d8d44c90fd 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -289,6 +289,7 @@ static LONG msaa_role_to_uia_control_type(LONG role) */ struct msaa_provider { IRawElementProviderSimple IRawElementProviderSimple_iface; + ILegacyIAccessibleProvider ILegacyIAccessibleProvider_iface; LONG refcount;
IAccessible *acc; @@ -330,9 +331,13 @@ static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderS
HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) { + struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface); + *ppv = NULL; if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) *ppv = iface; + else if (IsEqualIID(riid, &IID_ILegacyIAccessibleProvider)) + *ppv = &msaa_prov->ILegacyIAccessibleProvider_iface; else return E_NOINTERFACE;
@@ -377,9 +382,20 @@ HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *ifac HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface, PATTERNID pattern_id, IUnknown **ret_val) { - FIXME("%p, %d, %p: stub!\n", iface, pattern_id, ret_val); + TRACE("%p, %d, %p\n", iface, pattern_id, ret_val); + *ret_val = NULL; - return E_NOTIMPL; + switch (pattern_id) + { + case UIA_LegacyIAccessiblePatternId: + return IRawElementProviderSimple_QueryInterface(iface, &IID_IUnknown, (void **)ret_val); + + default: + FIXME("Unimplemented patternId %d\n", pattern_id); + break; + } + + return S_OK; }
HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface, @@ -465,6 +481,152 @@ static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = { msaa_provider_get_HostRawElementProvider, };
+/* + * ILegacyIAccessibleProvider interface for UiaProviderFromIAccessible + * providers. + */ +static inline struct msaa_provider *impl_from_msaa_acc_provider(ILegacyIAccessibleProvider *iface) +{ + return CONTAINING_RECORD(iface, struct msaa_provider, ILegacyIAccessibleProvider_iface); +} + +static HRESULT WINAPI msaa_acc_provider_QueryInterface(ILegacyIAccessibleProvider *iface, REFIID riid, void **ppv) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface); + return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI msaa_acc_provider_AddRef(ILegacyIAccessibleProvider *iface) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface); + return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI msaa_acc_provider_Release(ILegacyIAccessibleProvider *iface) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface); + return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI msaa_acc_provider_Select(ILegacyIAccessibleProvider *iface, LONG select_flags) +{ + FIXME("%p, %#lx: stub!\n", iface, select_flags); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_DoDefaultAction(ILegacyIAccessibleProvider *iface) +{ + FIXME("%p: stub!\n", iface); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_SetValue(ILegacyIAccessibleProvider *iface, LPCWSTR val) +{ + FIXME("%p, %p<%s>: stub!\n", iface, val, debugstr_w(val)); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_GetIAccessible(ILegacyIAccessibleProvider *iface, + IAccessible **out_acc) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface); + + TRACE("%p, %p\n", iface, out_acc); + + IAccessible_AddRef(msaa_prov->acc); + *out_acc = msaa_prov->acc; + + return S_OK; +} + +static HRESULT WINAPI msaa_acc_provider_get_ChildId(ILegacyIAccessibleProvider *iface, int *out_cid) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface); + + TRACE("%p, %p\n", iface, out_cid); + *out_cid = V_I4(&msaa_prov->cid); + + return S_OK; +} + +static HRESULT WINAPI msaa_acc_provider_get_Name(ILegacyIAccessibleProvider *iface, BSTR *out_name) +{ + FIXME("%p, %p: stub!\n", iface, out_name); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_Value(ILegacyIAccessibleProvider *iface, BSTR *out_value) +{ + FIXME("%p, %p: stub!\n", iface, out_value); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_Description(ILegacyIAccessibleProvider *iface, + BSTR *out_description) +{ + FIXME("%p, %p: stub!\n", iface, out_description); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_Role(ILegacyIAccessibleProvider *iface, DWORD *out_role) +{ + FIXME("%p, %p: stub!\n", iface, out_role); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_State(ILegacyIAccessibleProvider *iface, DWORD *out_state) +{ + FIXME("%p, %p: stub!\n", iface, out_state); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_Help(ILegacyIAccessibleProvider *iface, BSTR *out_help) +{ + FIXME("%p, %p: stub!\n", iface, out_help); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_KeyboardShortcut(ILegacyIAccessibleProvider *iface, + BSTR *out_kbd_shortcut) +{ + FIXME("%p, %p: stub!\n", iface, out_kbd_shortcut); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_GetSelection(ILegacyIAccessibleProvider *iface, + SAFEARRAY **out_selected) +{ + FIXME("%p, %p: stub!\n", iface, out_selected); + return E_NOTIMPL; +} + +static HRESULT WINAPI msaa_acc_provider_get_DefaultAction(ILegacyIAccessibleProvider *iface, + BSTR *out_default_action) +{ + FIXME("%p, %p: stub!\n", iface, out_default_action); + return E_NOTIMPL; +} + +static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = { + msaa_acc_provider_QueryInterface, + msaa_acc_provider_AddRef, + msaa_acc_provider_Release, + msaa_acc_provider_Select, + msaa_acc_provider_DoDefaultAction, + msaa_acc_provider_SetValue, + msaa_acc_provider_GetIAccessible, + msaa_acc_provider_get_ChildId, + msaa_acc_provider_get_Name, + msaa_acc_provider_get_Value, + msaa_acc_provider_get_Description, + msaa_acc_provider_get_Role, + msaa_acc_provider_get_State, + msaa_acc_provider_get_Help, + msaa_acc_provider_get_KeyboardShortcut, + msaa_acc_provider_GetSelection, + msaa_acc_provider_get_DefaultAction, +}; + /*********************************************************************** * UiaProviderFromIAccessible (uiautomationcore.@) */ @@ -520,6 +682,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD return E_OUTOFMEMORY;
msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl; + msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl; msaa_prov->refcount = 1; msaa_prov->hwnd = hwnd; variant_init_i4(&msaa_prov->cid, child_id);
V3: used HRESULT for `msaa_acc_prop_match`, and split accName comparison into multiple if statements.
This merge request was approved by Huw Davies.