From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 134 +++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 58 ++++++++- 2 files changed, 188 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index b010711c2bb..a92f15c6617 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -12487,6 +12487,139 @@ static void test_GetRootElement(IUIAutomation *uia_iface) UiaRegisterProviderCallback(NULL); }
+static const struct prov_method_sequence node_from_focus_seq1[]; +static const struct prov_method_sequence node_from_focus_seq6[]; +static void test_GetFocusedElement(IUIAutomation *uia_iface) +{ + struct Provider_prop_override prop_override; + IUIAutomationCacheRequest *cache_req; + IUIAutomationElement *element; + HRESULT hr; + VARIANT v; + HWND hwnd; + int i; + + hwnd = create_test_hwnd("test_GetFocusedElement class"); + UiaRegisterProviderCallback(test_uia_provider_callback); + + cache_req = NULL; + hr = IUIAutomation_CreateCacheRequest(uia_iface, &cache_req); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cache_req, "cache_req == NULL\n"); + + /* Set clientside providers for our test window and the desktop. */ + set_clientside_providers_for_hwnd(&Provider_proxy, &Provider_nc, &Provider_hwnd, GetDesktopWindow()); + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface; + + set_clientside_providers_for_hwnd(NULL, &Provider_nc2, &Provider_hwnd2, hwnd); + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd, TRUE); + Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface; + prov_root = &Provider.IRawElementProviderSimple_iface; + Provider.ignore_hwnd_prop = TRUE; + + /* NULL input argument tests. */ + hr = IUIAutomation_GetFocusedElement(uia_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IUIAutomation_GetFocusedElementBuildCache(uia_iface, cache_req, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + element = (void *)0xdeadbeef; + hr = IUIAutomation_GetFocusedElementBuildCache(uia_iface, NULL, &element); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!element, "element != NULL\n"); + + /* Test GetFocusedElement. */ + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + hr = IUIAutomation_GetFocusedElement(uia_iface, &element); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!element, "element == NULL\n"); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + + hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_ProviderDescriptionPropertyId, TRUE, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), GetDesktopWindow()); + 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(node_from_focus_seq1, "node_from_focus_seq1"); + IUIAutomationElement_Release(element); + + /* Test BuildCache variant. */ + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + hr = IUIAutomation_GetFocusedElementBuildCache(uia_iface, cache_req, &element); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!element, "element == NULL\n"); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + + hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_ProviderDescriptionPropertyId, TRUE, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), GetDesktopWindow()); + 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(node_from_focus_seq1, "node_from_focus_seq1"); + IUIAutomationElement_Release(element); + + /* + * GetFocusedElement returns UIA_E_ELEMENTNOTAVAILABLE when no provider + * matches our view condition, GetFocusedElementBuildCache returns E_FAIL. + */ + variant_init_bool(&v, FALSE); + set_property_override(&prop_override, UIA_IsControlElementPropertyId, &v); + set_provider_prop_override(&Provider2, &prop_override, 1); + + Provider_nc.focus_prov = NULL; + Provider_hwnd.focus_prov = &Provider_hwnd2.IRawElementProviderFragment_iface; + Provider.focus_prov = &Provider2.IRawElementProviderFragment_iface; + for (i = 0; i < 2; i++) + { + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT_MULTI(prov_callback_nonclient, 2); + SET_EXPECT_MULTI(prov_callback_proxy, 2); + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + element = (void *)0xdeadbeef; + if (!i) + { + hr = IUIAutomation_GetFocusedElement(uia_iface, &element); + ok(hr == UIA_E_ELEMENTNOTAVAILABLE, "Unexpected hr %#lx.\n", hr); + } + else + { + hr = IUIAutomation_GetFocusedElementBuildCache(uia_iface, cache_req, &element); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + } + ok(!element, "element != NULL\n"); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED_MULTI(prov_callback_nonclient, 2); + todo_wine CHECK_CALLED_MULTI(prov_callback_proxy, 2); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + + ok_method_sequence(node_from_focus_seq6, "node_from_focus_seq6"); + } + set_provider_prop_override(&Provider2, NULL, 0); + + base_hwnd_prov = nc_prov = proxy_prov = prov_root = NULL; + IUIAutomationCacheRequest_Release(cache_req); + UiaRegisterProviderCallback(NULL); + DestroyWindow(hwnd); + UnregisterClassA("test_GetFocusedElement class", NULL); +} + struct uia_com_classes { const GUID *clsid; const GUID *iid; @@ -12594,6 +12727,7 @@ static void test_CUIAutomation(void) test_Element_cache_methods(uia_iface); test_Element_Find(uia_iface); test_GetRootElement(uia_iface); + test_GetFocusedElement(uia_iface);
IUIAutomation_Release(uia_iface); CoUninitialize(); diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 6cba9fd46db..bcb23f38c56 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -2816,8 +2816,30 @@ static HRESULT WINAPI uia_iface_ElementFromPoint(IUIAutomation6 *iface, POINT pt
static HRESULT WINAPI uia_iface_GetFocusedElement(IUIAutomation6 *iface, IUIAutomationElement **out_elem) { - FIXME("%p, %p: stub\n", iface, out_elem); - return E_NOTIMPL; + IUIAutomationCacheRequest *cache_req; + HRESULT hr; + + TRACE("%p, %p\n", iface, out_elem); + + if (!out_elem) + return E_POINTER; + + *out_elem = NULL; + hr = create_uia_cache_request_iface(&cache_req); + if (FAILED(hr)) + return hr; + + hr = IUIAutomation6_GetFocusedElementBuildCache(iface, cache_req, out_elem); + IUIAutomationCacheRequest_Release(cache_req); + + /* + * Failure to get a focused element returns E_FAIL from the BuildCache + * method, but UIA_E_ELEMENTNOTAVAILABLE from this one. + */ + if (!(*out_elem) && hr == E_FAIL) + hr = UIA_E_ELEMENTNOTAVAILABLE; + + return hr; }
static HRESULT WINAPI uia_iface_GetRootElementBuildCache(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req, @@ -2844,8 +2866,36 @@ static HRESULT WINAPI uia_iface_ElementFromPointBuildCache(IUIAutomation6 *iface static HRESULT WINAPI uia_iface_GetFocusedElementBuildCache(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req, IUIAutomationElement **out_elem) { - FIXME("%p, %p, %p: stub\n", iface, cache_req, out_elem); - return E_NOTIMPL; + struct uia_iface *uia_iface = impl_from_IUIAutomation6(iface); + struct UiaCacheRequest *cache_req_struct; + BSTR tree_struct; + SAFEARRAY *sa; + HRESULT hr; + + TRACE("%p, %p, %p\n", iface, cache_req, out_elem); + + if (!out_elem) + return E_POINTER; + + *out_elem = NULL; + hr = get_uia_cache_request_struct_from_iface(cache_req, &cache_req_struct); + if (FAILED(hr)) + return hr; + + hr = UiaNodeFromFocus(cache_req_struct, &sa, &tree_struct); + if (SUCCEEDED(hr)) + { + if (!sa) + { + SysFreeString(tree_struct); + return E_FAIL; + } + + hr = create_uia_element_from_cache_req(out_elem, uia_iface->is_cui8, cache_req_struct, 0, sa, tree_struct); + SafeArrayDestroy(sa); + } + + return hr; }
static HRESULT WINAPI uia_iface_CreateTreeWalker(IUIAutomation6 *iface, IUIAutomationCondition *cond,