1
0
Fork 0
mirror of synced 2025-03-07 03:53:26 +01:00

uiautomationcore: Implement IUIAutomation::GetFocusedElement{BuildCacheRequest}.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-03-24 13:14:05 -04:00 committed by Alexandre Julliard
parent e070e9b476
commit 5bd4090705
2 changed files with 264 additions and 4 deletions

View file

@ -12493,6 +12493,213 @@ static void test_GetRootElement(IUIAutomation *uia_iface)
UiaRegisterProviderCallback(NULL);
}
#define test_get_focused_elem( uia_iface, cache_req, exp_hr, exp_node_desc, proxy_cback_count, base_hwnd_cback_count, \
nc_cback_count, win_get_obj_count, child_win_get_obj_count, proxy_cback_todo, \
base_hwnd_cback_todo, nc_cback_todo, win_get_obj_todo, child_win_get_obj_todo ) \
test_get_focused_elem_( (uia_iface), (cache_req), (exp_hr), (exp_node_desc), (proxy_cback_count), (base_hwnd_cback_count), \
(nc_cback_count), (win_get_obj_count), (child_win_get_obj_count), (proxy_cback_todo), \
(base_hwnd_cback_todo), (nc_cback_todo), (win_get_obj_todo), (child_win_get_obj_todo), __FILE__, __LINE__)
static void test_get_focused_elem_(IUIAutomation *uia_iface, IUIAutomationCacheRequest *cache_req, HRESULT exp_hr,
struct node_provider_desc *exp_node_desc, int proxy_cback_count, int base_hwnd_cback_count, int nc_cback_count,
int win_get_obj_count, int child_win_get_obj_count, BOOL proxy_cback_todo, BOOL base_hwnd_cback_todo,
BOOL nc_cback_todo, BOOL win_get_obj_todo, BOOL child_win_get_obj_todo, const char *file, int line)
{
IUIAutomationElement *element = NULL;
HRESULT hr;
VARIANT v;
SET_EXPECT_MULTI(prov_callback_base_hwnd, base_hwnd_cback_count);
SET_EXPECT_MULTI(prov_callback_nonclient, nc_cback_count);
SET_EXPECT_MULTI(prov_callback_proxy, proxy_cback_count);
SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, win_get_obj_count);
SET_EXPECT_MULTI(child_winproc_GETOBJECT_UiaRoot, child_win_get_obj_count);
if (cache_req)
hr = IUIAutomation_GetFocusedElementBuildCache(uia_iface, cache_req, &element);
else
hr = IUIAutomation_GetFocusedElement(uia_iface, &element);
ok_(file, line)(hr == exp_hr, "Unexpected hr %#lx.\n", hr);
todo_wine_if(base_hwnd_cback_todo) CHECK_CALLED_MULTI(prov_callback_base_hwnd, base_hwnd_cback_count);
todo_wine_if(proxy_cback_todo) CHECK_CALLED_MULTI(prov_callback_proxy, proxy_cback_count);
todo_wine_if(nc_cback_todo) CHECK_CALLED_MULTI(prov_callback_nonclient, nc_cback_count);
todo_wine_if(win_get_obj_todo) CHECK_CALLED_MULTI(winproc_GETOBJECT_UiaRoot, win_get_obj_count);
todo_wine_if(child_win_get_obj_todo) CHECK_CALLED_MULTI(child_winproc_GETOBJECT_UiaRoot, child_win_get_obj_count);
if (exp_node_desc->prov_count)
{
ok_(file, line)(!!element, "element == NULL\n");
hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_ProviderDescriptionPropertyId, TRUE, &v);
ok_(file, line)(hr == S_OK, "Unexpected hr %#lx\n", hr);
test_node_provider_desc_(exp_node_desc, V_BSTR(&v), file, line);
VariantClear(&v);
IUIAutomationElement_Release(element);
}
else
ok_(file, line)(!element, "element != NULL\n");
}
static void test_GetFocusedElement(IUIAutomation *uia_iface)
{
struct Provider_prop_override prop_override;
struct node_provider_desc exp_node_desc;
IUIAutomationCacheRequest *cache_req;
IUIAutomationElement *element;
HWND hwnd, hwnd_child;
HRESULT hr;
VARIANT v;
hwnd = create_test_hwnd("test_GetFocusedElement class");
hwnd_child = create_child_test_hwnd("test_GetFocusedElement child class", hwnd);
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 windows and the desktop. Same
* tests as UiaNodeFromFocus, just with COM methods.
*/
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;
set_clientside_providers_for_hwnd(NULL, &Provider_nc3, &Provider_hwnd3, hwnd_child);
initialize_provider(&Provider2, ProviderOptions_ServerSideProvider, hwnd_child, TRUE);
Provider2.frag_root = &Provider2.IRawElementProviderFragmentRoot_iface;
child_win_prov_root = &Provider2.IRawElementProviderSimple_iface;
Provider2.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");
/*
* None of the providers for the desktop node return a provider from
* IRawElementProviderFragmentRoot::GetFocus, so we just get the
* desktop node.
*/
method_sequences_enabled = FALSE;
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), GetDesktopWindow());
add_provider_desc(&exp_node_desc, L"Main", L"Provider_proxy", TRUE);
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc", FALSE);
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd", FALSE);
test_get_focused_elem(uia_iface, NULL, S_OK, &exp_node_desc, 1, 1, 1, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
test_get_focused_elem(uia_iface, cache_req, S_OK, &exp_node_desc, 1, 1, 1, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
/* Provider_hwnd returns Provider_hwnd2 from GetFocus. */
Provider_hwnd.focus_prov = &Provider_hwnd2.IRawElementProviderFragment_iface;
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), hwnd);
add_provider_desc(&exp_node_desc, L"Main", L"Provider", TRUE);
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc2", FALSE);
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd2", FALSE);
test_get_focused_elem(uia_iface, NULL, S_OK, &exp_node_desc, 2, 1, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
test_get_focused_elem(uia_iface, cache_req, S_OK, &exp_node_desc, 2, 1, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
/*
* Provider_proxy returns Provider from GetFocus. The provider that
* creates the node will not have GetFocus called on it to avoid returning
* the same provider twice. Similarly, on nodes other than the desktop
* node, the HWND provider will not have GetFocus called on it.
*/
Provider_hwnd.focus_prov = NULL;
Provider_proxy.focus_prov = &Provider.IRawElementProviderFragment_iface;
Provider.focus_prov = Provider_hwnd2.focus_prov = &Provider2.IRawElementProviderFragment_iface;
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), hwnd);
add_provider_desc(&exp_node_desc, L"Main", L"Provider", TRUE);
add_provider_desc(&exp_node_desc, L"Nonclient", L"Provider_nc2", FALSE);
add_provider_desc(&exp_node_desc, L"Hwnd", L"Provider_hwnd2", FALSE);
test_get_focused_elem(uia_iface, NULL, S_OK, &exp_node_desc, 2, 2, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
test_get_focused_elem(uia_iface, cache_req, S_OK, &exp_node_desc, 2, 2, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
/*
* Provider_nc returns Provider_nc2 from GetFocus, Provider returns
* Provider2, Provider_nc3 returns Provider_child.
*/
initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
Provider_proxy.focus_prov = Provider_hwnd.focus_prov = NULL;
Provider_nc.focus_prov = &Provider_nc2.IRawElementProviderFragment_iface;
Provider.focus_prov = &Provider2.IRawElementProviderFragment_iface;
Provider_nc3.focus_prov = &Provider_child.IRawElementProviderFragment_iface;
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
add_provider_desc(&exp_node_desc, L"Main", L"Provider_child", TRUE);
test_get_focused_elem(uia_iface, NULL, S_OK, &exp_node_desc, 2, 3, 2, 2, 1, TRUE, FALSE, FALSE, TRUE, FALSE);
test_get_focused_elem(uia_iface, cache_req, S_OK, &exp_node_desc, 2, 3, 2, 2, 1, TRUE, FALSE, FALSE, TRUE, FALSE);
/*
* Provider_proxy returns Provider_child_child from GetFocus. The focus
* provider is normalized against the cache request view condition.
* Provider_child_child and its ancestors don't match the cache request
* view condition, so we'll get no provider.
*/
initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
initialize_provider(&Provider_child_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
provider_add_child(&Provider, &Provider_child);
provider_add_child(&Provider_child, &Provider_child_child);
Provider_proxy.focus_prov = &Provider_child_child.IRawElementProviderFragment_iface;
Provider_nc.focus_prov = Provider_hwnd.focus_prov = NULL;
variant_init_bool(&v, FALSE);
set_property_override(&prop_override, UIA_IsControlElementPropertyId, &v);
set_provider_prop_override(&Provider_child_child, &prop_override, 1);
set_provider_prop_override(&Provider_child, &prop_override, 1);
set_provider_prop_override(&Provider, &prop_override, 1);
/*
* GetFocusedElement returns UIA_E_ELEMENTNOTAVAILABLE when no provider
* matches our view condition, GetFocusedElementBuildCache returns E_FAIL.
*/
init_node_provider_desc(&exp_node_desc, 0, NULL);
test_get_focused_elem(uia_iface, NULL, UIA_E_ELEMENTNOTAVAILABLE,
&exp_node_desc, 2, 2, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
test_get_focused_elem(uia_iface, cache_req, E_FAIL,
&exp_node_desc, 2, 2, 2, 1, 0, TRUE, FALSE, FALSE, FALSE, FALSE);
/* This time, Provider_child matches our view condition. */
set_provider_prop_override(&Provider_child, NULL, 0);
init_node_provider_desc(&exp_node_desc, GetCurrentProcessId(), NULL);
add_provider_desc(&exp_node_desc, L"Main", L"Provider_child", TRUE);
test_get_focused_elem(uia_iface, NULL, S_OK, &exp_node_desc, 1, 1, 1, 0, 0, FALSE, FALSE, FALSE, FALSE, FALSE);
method_sequences_enabled = TRUE;
initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, TRUE);
initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
initialize_provider(&Provider_child_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
base_hwnd_prov = nc_prov = proxy_prov = prov_root = NULL;
IUIAutomationCacheRequest_Release(cache_req);
UiaRegisterProviderCallback(NULL);
DestroyWindow(hwnd);
UnregisterClassA("test_GetFocusedElement class", NULL);
UnregisterClassA("test_GetFocusedElement child class", NULL);
}
struct uia_com_classes {
const GUID *clsid;
const GUID *iid;
@ -12600,6 +12807,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();

View file

@ -2814,10 +2814,61 @@ static HRESULT WINAPI uia_iface_ElementFromPoint(IUIAutomation6 *iface, POINT pt
return E_NOTIMPL;
}
static HRESULT uia_get_focused_element(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req,
BOOL use_default_cache_req, IUIAutomationElement **out_elem)
{
struct uia_iface *uia_iface = impl_from_IUIAutomation6(iface);
struct UiaCacheRequest *cache_req_struct;
BSTR tree_struct;
SAFEARRAY *sa;
HRESULT hr;
if (!out_elem)
return E_POINTER;
*out_elem = NULL;
if (use_default_cache_req)
{
hr = create_uia_cache_request_iface(&cache_req);
if (FAILED(hr))
return hr;
}
hr = get_uia_cache_request_struct_from_iface(cache_req, &cache_req_struct);
if (FAILED(hr))
goto exit;
hr = UiaNodeFromFocus(cache_req_struct, &sa, &tree_struct);
if (SUCCEEDED(hr))
{
if (!sa)
{
/*
* Failure to get a focused element returns E_FAIL from the BuildCache
* method, but UIA_E_ELEMENTNOTAVAILABLE from the default cache
* request method.
*/
hr = use_default_cache_req ? UIA_E_ELEMENTNOTAVAILABLE : E_FAIL;
SysFreeString(tree_struct);
goto exit;
}
hr = create_uia_element_from_cache_req(out_elem, uia_iface->is_cui8, cache_req_struct, 0, sa, tree_struct);
SafeArrayDestroy(sa);
}
exit:
if (use_default_cache_req)
IUIAutomationCacheRequest_Release(cache_req);
return hr;
}
static HRESULT WINAPI uia_iface_GetFocusedElement(IUIAutomation6 *iface, IUIAutomationElement **out_elem)
{
FIXME("%p, %p: stub\n", iface, out_elem);
return E_NOTIMPL;
TRACE("%p, %p\n", iface, out_elem);
return uia_get_focused_element(iface, NULL, TRUE, out_elem);
}
static HRESULT WINAPI uia_iface_GetRootElementBuildCache(IUIAutomation6 *iface, IUIAutomationCacheRequest *cache_req,
@ -2844,8 +2895,9 @@ 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;
TRACE("%p, %p, %p\n", iface, cache_req, out_elem);
return uia_get_focused_element(iface, cache_req, FALSE, out_elem);
}
static HRESULT WINAPI uia_iface_CreateTreeWalker(IUIAutomation6 *iface, IUIAutomationCondition *cond,