From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 845 +++++++++++++++++++++ dlls/uiautomationcore/uia_client.c | 149 +++- dlls/uiautomationcore/uia_main.c | 5 - 3 files changed, 987 insertions(+), 12 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1aa7b2353ba..62826430347 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -68,7 +68,12 @@ static HRESULT (WINAPI *pUiaDisconnectProvider)(IRawElementProviderSimple *); #define UIA_RUNTIME_ID_PREFIX 42
DEFINE_EXPECT(winproc_GETOBJECT_CLIENT); +DEFINE_EXPECT(prov_callback_base_hwnd); +DEFINE_EXPECT(prov_callback_nonclient); +DEFINE_EXPECT(prov_callback_proxy); +DEFINE_EXPECT(prov_callback_parent_proxy); DEFINE_EXPECT(winproc_GETOBJECT_UiaRoot); +DEFINE_EXPECT(child_winproc_GETOBJECT_UiaRoot); DEFINE_EXPECT(Accessible_accNavigate); DEFINE_EXPECT(Accessible_get_accParent); DEFINE_EXPECT(Accessible_get_accChildCount); @@ -1097,6 +1102,7 @@ static struct Provider IRawElementProviderSimple IRawElementProviderSimple_iface; IRawElementProviderFragment IRawElementProviderFragment_iface; IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface; + IRawElementProviderHwndOverride IRawElementProviderHwndOverride_iface; LONG ref;
const char *prov_name; @@ -1109,7 +1115,9 @@ static struct Provider int runtime_id[2]; DWORD last_call_tid; BOOL ignore_hwnd_prop; + HWND override_hwnd; } Provider, Provider2, Provider_child, Provider_child2; +static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override;
static const WCHAR *uia_bstr_prop_str = L"uia-string"; static const ULONG uia_i4_prop_val = 0xdeadbeef; @@ -1167,6 +1175,7 @@ enum { FRAG_NAVIGATE, FRAG_GET_RUNTIME_ID, FRAG_GET_FRAGMENT_ROOT, + HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, };
static const char *prov_method_str[] = { @@ -1176,6 +1185,7 @@ static const char *prov_method_str[] = { "Navigate", "GetRuntimeId", "get_FragmentRoot", + "GetOverrideProviderForHwnd", };
static const char *get_prov_method_str(int method) @@ -1491,6 +1501,8 @@ HRESULT WINAPI ProviderSimple_QueryInterface(IRawElementProviderSimple *iface, R *ppv = &This->IRawElementProviderFragment_iface; else if (IsEqualIID(riid, &IID_IRawElementProviderFragmentRoot)) *ppv = &This->IRawElementProviderFragmentRoot_iface; + else if (IsEqualIID(riid, &IID_IRawElementProviderHwndOverride)) + *ppv = &This->IRawElementProviderHwndOverride_iface; else return E_NOINTERFACE;
@@ -1924,11 +1936,60 @@ static const IRawElementProviderFragmentRootVtbl ProviderFragmentRootVtbl = { ProviderFragmentRoot_GetFocus, };
+static inline struct Provider *impl_from_ProviderHwndOverride(IRawElementProviderHwndOverride *iface) +{ + return CONTAINING_RECORD(iface, struct Provider, IRawElementProviderHwndOverride_iface); +} + +static HRESULT WINAPI ProviderHwndOverride_QueryInterface(IRawElementProviderHwndOverride *iface, REFIID riid, + void **ppv) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_QueryInterface(&Provider->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI ProviderHwndOverride_AddRef(IRawElementProviderHwndOverride *iface) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_AddRef(&Provider->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI ProviderHwndOverride_Release(IRawElementProviderHwndOverride *iface) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_Release(&Provider->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI ProviderHwndOverride_GetOverrideProviderForHwnd(IRawElementProviderHwndOverride *iface, + HWND hwnd, IRawElementProviderSimple **ret_val) +{ + struct Provider *This = impl_from_ProviderHwndOverride(iface); + + add_method_call(This, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER); + + *ret_val = NULL; + if (This->override_hwnd == hwnd) + { + return IRawElementProviderSimple_QueryInterface(&Provider_override.IRawElementProviderSimple_iface, + &IID_IRawElementProviderSimple, (void **)ret_val); + } + + return S_OK; +} + +static const IRawElementProviderHwndOverrideVtbl ProviderHwndOverrideVtbl = { + ProviderHwndOverride_QueryInterface, + ProviderHwndOverride_AddRef, + ProviderHwndOverride_Release, + ProviderHwndOverride_GetOverrideProviderForHwnd, +}; + static struct Provider Provider = { { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider", NULL, NULL, @@ -1940,6 +2001,7 @@ static struct Provider Provider2 = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider2", NULL, NULL, @@ -1951,6 +2013,7 @@ static struct Provider Provider_child = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider_child", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, @@ -1962,12 +2025,77 @@ static struct Provider Provider_child2 = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider_child2", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, ProviderOptions_ServerSideProvider, 0, 0, };
+static struct Provider Provider_hwnd = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_hwnd", + NULL, NULL, + ProviderOptions_ClientSideProvider, 0, 0, +}; + +static struct Provider Provider_nc = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_nc", + NULL, NULL, + ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider, + 0, 0, +}; + +static struct Provider Provider_proxy = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_proxy", + NULL, NULL, + ProviderOptions_ClientSideProvider, + 0, 0, +}; + +static struct Provider Provider_proxy2 = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_proxy2", + NULL, NULL, + ProviderOptions_ClientSideProvider, + 0, 0, +}; + +static struct Provider Provider_override = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_override", + NULL, NULL, + ProviderOptions_ServerSideProvider | ProviderOptions_OverrideProvider, + 0, 0, +}; + static IAccessible *acc_client; static IRawElementProviderSimple *prov_root; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -2001,6 +2129,30 @@ static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR return DefWindowProcA(hwnd, message, wParam, lParam); }
+static IRawElementProviderSimple *child_win_prov_root; +static LRESULT WINAPI child_test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_GETOBJECT: + if (lParam == UiaRootObjectId) + { + CHECK_EXPECT(child_winproc_GETOBJECT_UiaRoot); + if (child_win_prov_root) + return UiaReturnRawElementProvider(hwnd, wParam, lParam, child_win_prov_root); + + break; + } + + break; + + default: + break; + } + + return DefWindowProcA(hwnd, message, wParam, lParam); +} + static void test_UiaHostProviderFromHwnd(void) { IRawElementProviderSimple *p, *p2; @@ -5829,6 +5981,696 @@ static void test_UiaNodeFromHandle(const char *name) prov_root = NULL; }
+static const struct prov_method_sequence reg_prov_cb1[] = { + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb2[] = { + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb3[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb4[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These four only done on Win10+. */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb5[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb6[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb7[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb8[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb9[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb10[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These four only done on Win10+. */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb11[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb12[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb13[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + /* Provider override only retrieved successfully on Win10v1809+ */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1507 and below. */ + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + /* Only done on Win10v1809+. */ + { &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + /* Only done on Win10v1809+. */ + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static IRawElementProviderSimple *base_hwnd_prov, *proxy_prov, *parent_proxy_prov, *nc_prov; +static SAFEARRAY WINAPI *test_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) +{ + IRawElementProviderSimple *elprov = NULL; + + switch (prov_type) + { + case ProviderType_BaseHwnd: + CHECK_EXPECT(prov_callback_base_hwnd); + elprov = base_hwnd_prov; + break; + + case ProviderType_Proxy: + if (Provider_proxy.hwnd == hwnd) + { + CHECK_EXPECT(prov_callback_proxy); + elprov = proxy_prov; + } + else if (hwnd == GetParent(Provider_proxy.hwnd)) + { + CHECK_EXPECT(prov_callback_parent_proxy); + elprov = parent_proxy_prov; + } + break; + + case ProviderType_NonClientArea: + CHECK_EXPECT(prov_callback_nonclient); + elprov = nc_prov; + break; + + default: + break; + } + + if (elprov) + { + SAFEARRAY *sa; + LONG idx = 0; + + sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1); + if (sa) + SafeArrayPutElement(sa, &idx, (void *)elprov); + + return sa; + } + + return NULL; +} + +static void test_UiaRegisterProviderCallback(void) +{ + HWND hwnd, hwnd2; + WNDCLASSA cls; + HUIANODE node; + HRESULT hr; + 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 = "UiaRegisterProviderCallback class"; + + RegisterClassA(&cls); + + cls.lpfnWndProc = child_test_wnd_proc; + cls.lpszClassName = "UiaRegisterProviderCallback child class"; + RegisterClassA(&cls); + + hwnd = CreateWindowA("UiaRegisterProviderCallback class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + hwnd2 = CreateWindowA("UiaRegisterProviderCallback child class", "Test child window", WS_CHILD, + 0, 0, 100, 100, hwnd, NULL, NULL, NULL); + + UiaRegisterProviderCallback(test_uia_provider_callback); + + /* No providers returned by UiaRootObjectId or the provider callback. */ + Provider_proxy.hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + /* Windows 7 returns S_OK with a NULL HUIANODE. */ + ok(hr == E_FAIL || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr); + ok(!node, "node != NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + /* Return only nonclient proxy provider. */ + base_hwnd_prov = proxy_prov = parent_proxy_prov = NULL; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(!!node, "node == NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", TRUE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb1, "reg_prov_cb1"); + + UiaNodeRelease(node); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + + /* Return only base_hwnd provider. */ + nc_prov = proxy_prov = parent_proxy_prov = NULL; + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(!!node, "node == NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", TRUE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb2, "reg_prov_cb2"); + + UiaNodeRelease(node); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + + /* Return providers for all ProviderTypes. */ + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface; + parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + Provider_proxy.hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!node, "node == NULL\n"); + ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider_proxy", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb3, "reg_prov_cb3"); + + UiaNodeRelease(node); + ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + + /* Return an override provider from Provider_proxy2. */ + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface; + parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!node, "node == NULL\n"); + ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + todo_wine ok(Provider_override.ref == 2, "Unexpected refcnt %ld\n", Provider_override.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider_proxy", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb4, "reg_prov_cb4"); + + /* + * Test the order that Providers are queried for properties. The order is: + * Override provider. + * Main provider. + * Nonclient provider. + * Hwnd provider. + * + * UI Automation tries to get a property from each in this order until one + * returns a value. If none do, the property isn't supported. + */ + if (Provider_override.ref == 2) + { + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb5, "reg_prov_cb5"); + } + + /* Property retrieved from Provider_proxy (Main) */ + Provider_override.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb6, "reg_prov_cb6"); + + /* Property retrieved from Provider_nc (Nonclient) */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb7, "reg_prov_cb7"); + + /* Property retrieved from Provider_hwnd (Hwnd) */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + Provider_nc.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb8, "reg_prov_cb8"); + + /* Property retrieved from none of the providers. */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v)); + ok_method_sequence(reg_prov_cb9, "reg_prov_cb9"); + + UiaNodeRelease(node); + ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_override.ref == 1, "Unexpected refcnt %ld\n", Provider_override.ref); + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = FALSE; + Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = FALSE; + + /* + * Provider_hwnd has ProviderOptions_UseComThreading, and COM hasn't been + * initialized. One provider failing will cause the entire node to fail + * creation on Win10+. + */ + Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider | ProviderOptions_UseComThreading; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == CO_E_NOTINITIALIZED || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr); + ok(!node || broken(!!node), "node != NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + ok_method_sequence(reg_prov_cb10, "reg_prov_cb10"); + UiaNodeRelease(node); + Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider; + + /* + * Provider returned by UiaRootObjectId on hwnd2. No ProviderType_Proxy + * callback for hwnd2. + */ + Provider.hwnd = hwnd2; + Provider.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb11, "reg_prov_cb11"); + + UiaNodeRelease(node); + + /* + * Provider returned by UiaRootObjectId on both HWNDs. Since Provider2 + * doesn't give an HWND override provider, UIA will attempt to get a proxy + * provider to check it for an HWND override provider. + */ + Provider.hwnd = hwnd2; + Provider2.hwnd = hwnd; + Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + prov_root = &Provider2.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb12, "reg_prov_cb12"); + + UiaNodeRelease(node); + + /* + * Provider returned by UiaRootObjectId on both HWNDs. Since Provider2 + * returns an HWND override, no ProviderType_Proxy callback for hwnd. + */ + Provider.hwnd = hwnd2; + Provider2.hwnd = hwnd; + Provider2.override_hwnd = Provider_override.hwnd = hwnd2; + Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = TRUE; + Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + prov_root = &Provider2.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb13, "reg_prov_cb13"); + + UiaNodeRelease(node); + + Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = FALSE; + UiaRegisterProviderCallback(NULL); + + DestroyWindow(hwnd); + UnregisterClassA("UiaRegisterProviderCallback class", NULL); + UnregisterClassA("UiaRegisterProviderCallback child class", NULL); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -5876,6 +6718,8 @@ START_TEST(uiautomation) test_UiaNodeFromHandle(argv[0]); else if (!strcmp(argv[2], "UiaNodeFromHandle_client_proc")) test_UiaNodeFromHandle_client_proc(); + else if (!strcmp(argv[2], "UiaRegisterProviderCallback")) + test_UiaRegisterProviderCallback();
FreeLibrary(uia_dll); return; @@ -5889,6 +6733,7 @@ START_TEST(uiautomation) test_UiaGetRuntimeId(); test_UiaHUiaNodeFromVariant(); launch_test_process(argv[0], "UiaNodeFromHandle"); + launch_test_process(argv[0], "UiaRegisterProviderCallback"); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 94046066354..05f7c027565 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -909,7 +909,7 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid return S_OK; }
-static HRESULT uia_get_provider_from_hwnd(struct uia_node *node); +static HRESULT uia_get_providers_for_hwnd(struct uia_node *node); HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers) { @@ -958,7 +958,11 @@ HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE }
if (node->hwnd && get_hwnd_providers) - uia_get_provider_from_hwnd(node); + { + hr = uia_get_providers_for_hwnd(node); + if (FAILED(hr)) + WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr); + }
hr = prepare_uia_node(node); if (FAILED(hr)) @@ -1406,9 +1410,9 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
if (node->hwnd) { - hr = uia_get_provider_from_hwnd(node); + hr = uia_get_providers_for_hwnd(node); if (FAILED(hr)) - WARN("uia_get_provider_from_hwnd failed with hr %#lx\n", hr); + WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr); }
hr = prepare_uia_node(node); @@ -1445,9 +1449,8 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
if (!args.lr) { - FIXME("No native UIA provider for hwnd %p, MSAA proxy currently unimplemented.\n", node->hwnd); uia_stop_client_thread(); - return E_NOTIMPL; + return S_FALSE; }
args.unwrap = GetCurrentThreadId() == GetWindowThreadProcessId(node->hwnd, NULL); @@ -1482,7 +1485,7 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode) list_init(&node->node_map_list_entry); node->ref = 1;
- hr = uia_get_provider_from_hwnd(node); + hr = uia_get_providers_for_hwnd(node); if (FAILED(hr)) { heap_free(node); @@ -1776,3 +1779,135 @@ HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
return S_OK; } + +static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) +{ + switch (prov_type) + { + case ProviderType_Proxy: + FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n"); + break; + + case ProviderType_NonClientArea: + FIXME("Default ProviderType_NonClientArea provider unimplemented.\n"); + break; + + case ProviderType_BaseHwnd: + FIXME("Default ProviderType_BaseHwnd provider unimplemented.\n"); + break; + + default: + break; + } + + return NULL; +} + +static UiaProviderCallback *uia_provider_callback = default_uia_provider_callback; + +static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type, + int node_prov_type) +{ + IRawElementProviderSimple *elprov; + LONG lbound, elems; + SAFEARRAY *sa; + IUnknown *unk; + VARTYPE vt; + HRESULT hr; + + if (!(sa = uia_provider_callback(node->hwnd, prov_type))) + return S_OK; + + hr = SafeArrayGetVartype(sa, &vt); + if (FAILED(hr) || (vt != VT_UNKNOWN)) + goto exit; + + hr = get_safearray_bounds(sa, &lbound, &elems); + if (FAILED(hr)) + goto exit; + + /* Returned SAFEARRAY can only have 1 element. */ + if (elems != 1) + { + WARN("Invalid element count %ld for returned SAFEARRAY\n", elems); + goto exit; + } + + hr = SafeArrayGetElement(sa, &lbound, &unk); + if (FAILED(hr)) + goto exit; + + hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov); + IUnknown_Release(unk); + if (FAILED(hr) || !elprov) + { + WARN("Failed to get IRawElementProviderSimple from returned SAFEARRAY.\n"); + hr = S_OK; + goto exit; + } + + hr = create_wine_uia_provider(node, elprov, node_prov_type); + IRawElementProviderSimple_Release(elprov); + +exit: + if (FAILED(hr)) + WARN("Failed to get clientside provider, hr %#lx\n", hr); + SafeArrayDestroy(sa); + return hr; +} + +static HRESULT uia_get_providers_for_hwnd(struct uia_node *node) +{ + HRESULT hr; + + hr = uia_get_provider_from_hwnd(node); + if (FAILED(hr)) + return hr; + + if (!node->prov[PROV_TYPE_MAIN]) + { + hr = uia_get_clientside_provider(node, ProviderType_Proxy, PROV_TYPE_MAIN); + if (FAILED(hr)) + return hr; + } + + if (!node->prov[PROV_TYPE_OVERRIDE]) + FIXME("Override provider callback currently unimplemented.\n"); + + if (!node->prov[PROV_TYPE_NONCLIENT]) + { + hr = uia_get_clientside_provider(node, ProviderType_NonClientArea, PROV_TYPE_NONCLIENT); + if (FAILED(hr)) + return hr; + } + + if (!node->prov[PROV_TYPE_HWND]) + { + hr = uia_get_clientside_provider(node, ProviderType_BaseHwnd, PROV_TYPE_HWND); + if (FAILED(hr)) + return hr; + } + + if (!node->prov_count) + { + if (uia_provider_callback == default_uia_provider_callback) + return E_NOTIMPL; + else + return E_FAIL; + } + + return S_OK; +} + +/*********************************************************************** + * UiaRegisterProviderCallback (uiautomationcore.@) + */ +void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) +{ + TRACE("(%p)\n", callback); + + if (callback) + uia_provider_callback = callback; + else + uia_provider_callback = default_uia_provider_callback; +} diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index c888b51a019..2c741398c82 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -317,11 +317,6 @@ HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple return S_OK; }
-void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) -{ - FIXME("(%p): stub\n", callback); -} - HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov;