Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/Makefile.in | 3 +- dlls/uiautomationcore/uia_main.c | 1 + dlls/uiautomationcore/uia_provider.c | 226 ++++++++++++++++++++ dlls/uiautomationcore/uiautomationcore.spec | 2 +- include/uiautomationcoreapi.h | 4 + 5 files changed, 234 insertions(+), 2 deletions(-) create mode 100644 dlls/uiautomationcore/uia_provider.c
diff --git a/dlls/uiautomationcore/Makefile.in b/dlls/uiautomationcore/Makefile.in index f0973fdec4c..bda3614f051 100644 --- a/dlls/uiautomationcore/Makefile.in +++ b/dlls/uiautomationcore/Makefile.in @@ -5,4 +5,5 @@ IMPORTS = uuid ole32 oleaut32 user32 EXTRADLLFLAGS = -Wb,--prefer-native
C_SRCS = \ - uia_main.c + uia_main.c \ + uia_provider.c diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index a303e71cf76..9f257684333 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -20,6 +20,7 @@
#include "initguid.h" #include "uiautomation.h" +#include "ocidl.h"
#include "wine/debug.h" #include "wine/heap.h" diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c new file mode 100644 index 00000000000..790593dbcab --- /dev/null +++ b/dlls/uiautomationcore/uia_provider.c @@ -0,0 +1,226 @@ +/* + * Copyright 2022 Connor McAdams for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define COBJMACROS + +#include "uiautomation.h" +#include "ocidl.h" + +#include "wine/debug.h" +#include "wine/heap.h" + +WINE_DEFAULT_DEBUG_CHANNEL(uiautomation); + +static void variant_init_i4(VARIANT *v, int val) +{ + V_VT(v) = VT_I4; + V_I4(v) = val; +} + +/* + * UiaProviderFromIAccessible IRawElementProviderSimple interface. + */ +struct msaa_provider { + IRawElementProviderSimple IRawElementProviderSimple_iface; + LONG refcount; + + IAccessible *acc; + VARIANT cid; + HWND hwnd; +}; + +static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface) +{ + return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface); +} + +HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IRawElementProviderSimple_AddRef(iface); + return S_OK; +} + +ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface); + ULONG refcount = InterlockedIncrement(&msaa_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + return refcount; +} + +ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface) +{ + struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface); + ULONG refcount = InterlockedDecrement(&msaa_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + if (!refcount) + { + IAccessible_Release(msaa_prov->acc); + heap_free(msaa_prov); + } + + return refcount; +} + +HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface, + enum ProviderOptions *ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading; + return S_OK; +} + +HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface, + PATTERNID pattern_id, IUnknown **ret_val) +{ + FIXME("%p, %d, %p: stub!\n", iface, pattern_id, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface, + PROPERTYID prop_id, VARIANT *ret_val) +{ + TRACE("%p, %d, %p\n", iface, prop_id, ret_val); + + VariantInit(ret_val); + switch (prop_id) + { + case UIA_ProviderDescriptionPropertyId: + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy"); + break; + + default: + FIXME("Unimplemented propertyId %d\n", prop_id); + break; + } + + return S_OK; +} + +HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface, + IRawElementProviderSimple **ret_val) +{ + FIXME("%p, %p: stub!\n", iface, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = { + msaa_provider_QueryInterface, + msaa_provider_AddRef, + msaa_provider_Release, + msaa_provider_get_ProviderOptions, + msaa_provider_GetPatternProvider, + msaa_provider_GetPropertyValue, + msaa_provider_get_HostRawElementProvider, +}; + +/*********************************************************************** + * UiaProviderFromIAccessible (uiautomationcore.@) + */ +HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags, + IRawElementProviderSimple **elprov) +{ + struct msaa_provider *msaa_prov; + IServiceProvider *serv_prov; + HWND hwnd = NULL; + IOleWindow *win; + HRESULT hr; + + TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov); + + if (elprov) + *elprov = NULL; + + if (!elprov) + return E_POINTER; + if (!acc) + return E_INVALIDARG; + + if (flags != UIA_PFIA_DEFAULT) + { + FIXME("unsupported flags %#lx\n", flags); + return E_NOTIMPL; + } + + hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov); + if (SUCCEEDED(hr)) + { + IUnknown *unk; + + hr = IServiceProvider_QueryService(serv_prov, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk); + if (SUCCEEDED(hr)) + { + WARN("Cannot wrap an oleacc proxy IAccessible!\n"); + IUnknown_Release(unk); + IServiceProvider_Release(serv_prov); + return E_INVALIDARG; + } + + IServiceProvider_Release(serv_prov); + } + + hr = IAccessible_QueryInterface(acc, &IID_IOleWindow, (void **)&win); + if (SUCCEEDED(hr)) + { + hr = IOleWindow_GetWindow(win, &hwnd); + if (FAILED(hr)) + hwnd = NULL; + IOleWindow_Release(win); + } + + if (!IsWindow(hwnd)) + { + VARIANT v, cid; + + VariantInit(&v); + variant_init_i4(&cid, CHILDID_SELF); + hr = IAccessible_accNavigate(acc, 10, cid, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_I4) + hwnd = ULongToHandle(V_I4(&v)); + + if (!IsWindow(hwnd)) + return E_FAIL; + } + + msaa_prov = heap_alloc(sizeof(*msaa_prov)); + if (!msaa_prov) + return E_OUTOFMEMORY; + + msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl; + msaa_prov->refcount = 1; + msaa_prov->hwnd = hwnd; + variant_init_i4(&msaa_prov->cid, child_id); + msaa_prov->acc = acc; + IAccessible_AddRef(acc); + *elprov = &msaa_prov->IRawElementProviderSimple_iface; + + return S_OK; +} diff --git a/dlls/uiautomationcore/uiautomationcore.spec b/dlls/uiautomationcore/uiautomationcore.spec index 82071bd2317..70d78d52085 100644 --- a/dlls/uiautomationcore/uiautomationcore.spec +++ b/dlls/uiautomationcore/uiautomationcore.spec @@ -83,7 +83,7 @@ @ stub UiaNodeRelease @ stub UiaPatternRelease #@ stub UiaProviderForNonClient -#@ stub UiaProviderFromIAccessible +@ stdcall UiaProviderFromIAccessible(ptr long long ptr) @ stub UiaRaiseAsyncContentLoadedEvent @ stdcall UiaRaiseAutomationEvent(ptr long) @ stdcall UiaRaiseAutomationPropertyChangedEvent(ptr long int128 int128) diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 563d5c602bd..22b3888dc6e 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -34,6 +34,9 @@ extern "C" { #define UiaAppendRuntimeId 3 #define UiaRootObjectId -25
+#define UIA_PFIA_DEFAULT 0x00 +#define UIA_PFIA_UNWRAP_BRIDGE 0x01 + DECLARE_HANDLE(HUIANODE); DECLARE_HANDLE(HUIAPATTERNOBJECT); DECLARE_HANDLE(HUIATEXTRANGE); @@ -71,6 +74,7 @@ void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *pCallback); LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wParam, LPARAM lParam, IRawElementProviderSimple *elprov); BOOL WINAPI UiaTextRangeRelease(HUIATEXTRANGE hobj); HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **elprov); +HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags, IRawElementProviderSimple **elprov);
#ifdef __cplusplus }
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/Makefile.in | 2 +- dlls/uiautomationcore/tests/uiautomation.c | 424 +++++++++++++++++++++ 2 files changed, 425 insertions(+), 1 deletion(-)
diff --git a/dlls/uiautomationcore/tests/Makefile.in b/dlls/uiautomationcore/tests/Makefile.in index fbd53507fbe..53ed6f6e380 100644 --- a/dlls/uiautomationcore/tests/Makefile.in +++ b/dlls/uiautomationcore/tests/Makefile.in @@ -1,5 +1,5 @@ TESTDLL = uiautomationcore.dll -IMPORTS = uiautomationcore user32 ole32 oleaut32 +IMPORTS = uiautomationcore user32 ole32 oleaut32 oleacc
C_SRCS = \ uiautomation.c diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 501875a20e7..246f8aba7c1 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -23,9 +23,322 @@ #include "windows.h" #include "initguid.h" #include "uiautomation.h" +#include "ocidl.h"
#include "wine/test.h"
+static HRESULT (WINAPI *pUiaProviderFromIAccessible)(IAccessible *, long, DWORD, IRawElementProviderSimple **); + +#define DEFINE_EXPECT(func) \ + static BOOL expect_ ## func = FALSE, called_ ## func = FALSE + +#define SET_EXPECT(func) \ + do { called_ ## func = FALSE; expect_ ## func = TRUE; } while(0) + +#define CHECK_EXPECT2(func) \ + do { \ + ok(expect_ ##func, "unexpected call " #func "\n"); \ + called_ ## func = TRUE; \ + }while(0) + +#define CHECK_EXPECT(func) \ + do { \ + CHECK_EXPECT2(func); \ + expect_ ## func = FALSE; \ + }while(0) + +#define CHECK_CALLED(func) \ + do { \ + ok(called_ ## func, "expected " #func "\n"); \ + expect_ ## func = called_ ## func = FALSE; \ + }while(0) + +DEFINE_EXPECT(Accessible_accNavigate); + +static LONG Accessible_ref = 1; +static IAccessible Accessible; +static IOleWindow OleWindow; +static HWND Accessible_hwnd = NULL; +static HWND OleWindow_hwnd = NULL; + +static BOOL check_variant_i4(VARIANT *v, int val) +{ + if (V_VT(v) == VT_I4 && V_I4(v) == val) + return TRUE; + + return FALSE; +} + +static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid, void **obj) +{ + *obj = NULL; + if (IsEqualIID(riid, &IID_IUnknown) || IsEqualIID(riid, &IID_IDispatch) || + IsEqualIID(riid, &IID_IAccessible)) + *obj = iface; + else if (IsEqualIID(riid, &IID_IOleWindow)) + *obj = &OleWindow; + else + return E_NOINTERFACE; + + IAccessible_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI Accessible_AddRef(IAccessible *iface) +{ + return InterlockedIncrement(&Accessible_ref); +} + +static ULONG WINAPI Accessible_Release(IAccessible *iface) +{ + return InterlockedDecrement(&Accessible_ref); +} + +static HRESULT WINAPI Accessible_GetTypeInfoCount(IAccessible *iface, UINT *pctinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetTypeInfo(IAccessible *iface, UINT iTInfo, + LCID lcid, ITypeInfo **out_tinfo) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_GetIDsOfNames(IAccessible *iface, REFIID riid, + LPOLESTR *rg_names, UINT name_count, LCID lcid, DISPID *rg_disp_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_Invoke(IAccessible *iface, DISPID disp_id_member, + REFIID riid, LCID lcid, WORD flags, DISPPARAMS *disp_params, + VARIANT *var_result, EXCEPINFO *excep_info, UINT *arg_err) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accParent(IAccessible *iface, IDispatch **out_parent) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accChildCount(IAccessible *iface, LONG *out_count) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accChild(IAccessible *iface, VARIANT child_id, + IDispatch **out_child) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accName(IAccessible *iface, VARIANT child_id, + BSTR *out_name) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accValue(IAccessible *iface, VARIANT child_id, + BSTR *out_value) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDescription(IAccessible *iface, VARIANT child_id, + BSTR *out_description) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accRole(IAccessible *iface, VARIANT child_id, + VARIANT *out_role) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accState(IAccessible *iface, VARIANT child_id, + VARIANT *out_state) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accHelp(IAccessible *iface, VARIANT child_id, + BSTR *out_help) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accHelpTopic(IAccessible *iface, + BSTR *out_help_file, VARIANT child_id, LONG *out_topic_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accKeyboardShortcut(IAccessible *iface, VARIANT child_id, + BSTR *out_kbd_shortcut) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accFocus(IAccessible *iface, VARIANT *pchild_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accSelection(IAccessible *iface, VARIANT *out_selection) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_get_accDefaultAction(IAccessible *iface, VARIANT child_id, + BSTR *out_default_action) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accSelect(IAccessible *iface, LONG select_flags, + VARIANT child_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accLocation(IAccessible *iface, LONG *out_left, + LONG *out_top, LONG *out_width, LONG *out_height, VARIANT child_id) +{ + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accNavigate(IAccessible *iface, LONG nav_direction, + VARIANT child_id_start, VARIANT *out_var) +{ + CHECK_EXPECT(Accessible_accNavigate); + VariantInit(out_var); + + /* + * This is an undocumented way for UI Automation to get an HWND for + * IAccessible's contained in a Direct Annotation wrapper object. + */ + if ((nav_direction == 10) && check_variant_i4(&child_id_start, CHILDID_SELF)) + { + V_VT(out_var) = VT_I4; + V_I4(out_var) = HandleToUlong(Accessible_hwnd); + return S_OK; + } + return S_FALSE; +} + +static HRESULT WINAPI Accessible_accHitTest(IAccessible *iface, LONG left, LONG top, + VARIANT *out_child_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_accDoDefaultAction(IAccessible *iface, VARIANT child_id) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_put_accName(IAccessible *iface, VARIANT child_id, + BSTR name) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static HRESULT WINAPI Accessible_put_accValue(IAccessible *iface, VARIANT child_id, + BSTR value) +{ + ok(0, "unexpected call\n"); + return E_NOTIMPL; +} + +static IAccessibleVtbl AccessibleVtbl = { + Accessible_QueryInterface, + Accessible_AddRef, + Accessible_Release, + Accessible_GetTypeInfoCount, + Accessible_GetTypeInfo, + Accessible_GetIDsOfNames, + Accessible_Invoke, + Accessible_get_accParent, + Accessible_get_accChildCount, + Accessible_get_accChild, + Accessible_get_accName, + Accessible_get_accValue, + Accessible_get_accDescription, + Accessible_get_accRole, + Accessible_get_accState, + Accessible_get_accHelp, + Accessible_get_accHelpTopic, + Accessible_get_accKeyboardShortcut, + Accessible_get_accFocus, + Accessible_get_accSelection, + Accessible_get_accDefaultAction, + Accessible_accSelect, + Accessible_accLocation, + Accessible_accNavigate, + Accessible_accHitTest, + Accessible_accDoDefaultAction, + Accessible_put_accName, + Accessible_put_accValue +}; + +static HRESULT WINAPI OleWindow_QueryInterface(IOleWindow *iface, REFIID riid, void **obj) +{ + return IAccessible_QueryInterface(&Accessible, riid, obj); +} + +static ULONG WINAPI OleWindow_AddRef(IOleWindow *iface) +{ + return IAccessible_AddRef(&Accessible); +} + +static ULONG WINAPI OleWindow_Release(IOleWindow *iface) +{ + return IAccessible_Release(&Accessible); +} + +static HRESULT WINAPI OleWindow_GetWindow(IOleWindow *iface, HWND *hwnd) +{ + *hwnd = OleWindow_hwnd; + return S_OK; +} + +static HRESULT WINAPI OleWindow_ContextSensitiveHelp(IOleWindow *iface, BOOL f_enter_mode) +{ + return E_NOTIMPL; +} + +static const IOleWindowVtbl OleWindowVtbl = { + OleWindow_QueryInterface, + OleWindow_AddRef, + OleWindow_Release, + OleWindow_GetWindow, + OleWindow_ContextSensitiveHelp +}; + +static IAccessible Accessible = {&AccessibleVtbl}; +static IOleWindow OleWindow = {&OleWindowVtbl}; + static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { return DefWindowProcA(hwnd, message, wParam, lParam); @@ -264,8 +577,119 @@ static void test_uia_reserved_value_ifaces(void) CoUninitialize(); }
+static void test_UiaProviderFromIAccessible(void) +{ + IRawElementProviderSimple *elprov; + enum ProviderOptions prov_opt; + IAccessible *acc; + WNDCLASSA cls; + HRESULT hr; + HWND hwnd; + VARIANT v; + + + cls.style = 0; + cls.lpfnWndProc = test_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "UiaProviderFromIAccessible class"; + + RegisterClassA(&cls); + + hwnd = CreateWindowA("UiaProviderFromIAccessible class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + hr = pUiaProviderFromIAccessible(NULL, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + + hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + /* + * UiaProviderFromIAccessible will not wrap an MSAA proxy, this is + * detected by checking for the 'IIS_IsOleaccProxy' service from the + * IServiceProvider interface. + */ + hr = CreateStdAccessibleObject(hwnd, OBJID_CLIENT, &IID_IAccessible, (void**)&acc); + ok(hr == S_OK, "got %#lx\n", hr); + ok(!!acc, "acc == NULL\n"); + + hr = pUiaProviderFromIAccessible(acc, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + IAccessible_Release(acc); + + /* Don't return an HWND from accNavigate or OleWindow. */ + SET_EXPECT(Accessible_accNavigate); + Accessible_hwnd = NULL; + OleWindow_hwnd = NULL; + hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(Accessible_accNavigate); + + /* Return an HWND from accNavigate, not OleWindow. */ + SET_EXPECT(Accessible_accNavigate); + Accessible_hwnd = hwnd; + OleWindow_hwnd = NULL; + hr = pUiaProviderFromIAccessible(&Accessible, CHILDID_SELF, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + CHECK_CALLED(Accessible_accNavigate); + ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref); + IRawElementProviderSimple_Release(elprov); + ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref); + + /* Return an HWND from OleWindow, not accNavigate. */ + Accessible_hwnd = NULL; + OleWindow_hwnd = hwnd; + hr = pUiaProviderFromIAccessible(&Accessible, 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); + + hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opt); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok((prov_opt == (ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading)) || + broken(prov_opt == ProviderOptions_ClientSideProvider), /* Windows < 10 1507 */ + "Unexpected provider options %#x\n", prov_opt); + + hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_ProviderDescriptionPropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_BSTR, "V_VT(&v) = %d\n", V_VT(&v)); + VariantClear(&v); + + IRawElementProviderSimple_Release(elprov); + ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref); + + /* ChildID other than CHILDID_SELF. */ + hr = pUiaProviderFromIAccessible(&Accessible, 1, UIA_PFIA_DEFAULT, &elprov); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Accessible_ref == 2, "Unexpected refcnt %ld\n", Accessible_ref); + IRawElementProviderSimple_Release(elprov); + ok(Accessible_ref == 1, "Unexpected refcnt %ld\n", Accessible_ref); + + DestroyWindow(hwnd); + UnregisterClassA("pUiaProviderFromIAccessible class", NULL); + Accessible_hwnd = NULL; + OleWindow_hwnd = NULL; +} + START_TEST(uiautomation) { + HMODULE uia_dll = LoadLibraryA("uiautomationcore.dll"); + test_UiaHostProviderFromHwnd(); test_uia_reserved_value_ifaces(); + if (uia_dll) + { + pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); + if (pUiaProviderFromIAccessible) + test_UiaProviderFromIAccessible(); + else + win_skip("UiaProviderFromIAccessible not exported by uiautomationcore.dll\n"); + + FreeLibrary(uia_dll); + } }