uiautomationcore: Implement UiaHasServerSideProvider.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2023-08-21 10:28:33 -04:00 committed by Alexandre Julliard
parent 815e3889c6
commit f0525a5ff6
3 changed files with 105 additions and 16 deletions

View file

@ -15302,6 +15302,64 @@ static void test_UiaAddEvent(const char *name)
UnregisterClassA("UiaAddEvent test class", NULL);
}
static const struct prov_method_sequence serverside_prov_seq[] = {
NODE_CREATE_SEQ2(&Provider),
/* Windows 10+ calls this. */
{ &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL },
{ 0 }
};
static void test_UiaHasServerSideProvider(void)
{
BOOL ret_val;
HWND hwnd;
CoInitializeEx(NULL, COINIT_MULTITHREADED);
hwnd = create_test_hwnd("UiaHasServerSideProvider test class");
/* NULL hwnd. */
ret_val = UiaHasServerSideProvider(NULL);
ok(!ret_val, "UiaHasServerSideProvider returned TRUE\n");
/* Desktop window has no serverside providers. */
UiaRegisterProviderCallback(test_uia_provider_callback);
ret_val = UiaHasServerSideProvider(GetDesktopWindow());
ok(!ret_val, "UiaHasServerSideProvider returned TRUE\n");
/* No provider to pass to UiaReturnRawElementProvider, returns FALSE. */
prov_root = NULL;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
ret_val = UiaHasServerSideProvider(hwnd);
ok(!ret_val, "UiaHasServerSideProvider returned TRUE\n");
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
/*
* Provider passed to UiaReturnRawElementProvider returns a failure from
* get_ProviderOptions. Returns FALSE.
*/
initialize_provider(&Provider, 0, hwnd, TRUE);
prov_root = &Provider.IRawElementProviderSimple_iface;
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
ret_val = UiaHasServerSideProvider(hwnd);
ok(!ret_val, "UiaHasServerSideProvider returned TRUE\n");
ok_method_sequence(node_from_hwnd1, NULL);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
/* Successfully return a provider from UiaReturnRawElementProvider. */
initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd, TRUE);
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
ret_val = UiaHasServerSideProvider(hwnd);
ok(ret_val, "UiaHasServerSideProvider returned FALSE\n");
ok_method_sequence(serverside_prov_seq, "serverside_prov_seq");
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
UiaRegisterProviderCallback(NULL);
prov_root = NULL;
CoUninitialize();
DestroyWindow(hwnd);
UnregisterClassA("UiaHasServerSideProvider test class", NULL);
}
/*
* Once a process returns a UI Automation provider with
* UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This
@ -15375,6 +15433,7 @@ START_TEST(uiautomation)
test_UiaGetRootNode();
test_UiaNodeFromFocus();
test_UiaAddEvent(argv[0]);
test_UiaHasServerSideProvider();
if (uia_dll)
{
pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible");

View file

@ -597,7 +597,7 @@ static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface)
return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface);
}
static HRESULT create_uia_node(struct uia_node **out_node)
static HRESULT create_uia_node(struct uia_node **out_node, int node_flags)
{
struct uia_node *node;
@ -609,6 +609,10 @@ static HRESULT create_uia_node(struct uia_node **out_node)
list_init(&node->prov_thread_list_entry);
list_init(&node->node_map_list_entry);
node->ref = 1;
if (node_flags & NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS)
node->ignore_clientside_hwnd_provs = TRUE;
if (node_flags & NODE_FLAG_NO_PREPARE)
node->no_prepare = TRUE;
*out_node = node;
return S_OK;
@ -620,6 +624,9 @@ static HRESULT prepare_uia_node(struct uia_node *node)
int i, prov_idx;
HRESULT hr;
if (node->no_prepare)
return S_OK;
/* Get the provider index for the provider that created the node. */
for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++)
{
@ -714,7 +721,7 @@ HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node)
}
}
hr = create_uia_node(&node);
hr = create_uia_node(&node, 0);
if (FAILED(hr))
return hr;
@ -1980,7 +1987,7 @@ HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE
else
prov_type = PROV_TYPE_MAIN;
hr = create_uia_node(&node);
hr = create_uia_node(&node, 0);
if (FAILED(hr))
return hr;
@ -2503,7 +2510,7 @@ HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
*huianode = NULL;
hr = create_uia_node(&node);
hr = create_uia_node(&node, 0);
if (FAILED(hr))
return hr;
@ -2564,25 +2571,20 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
return SendMessageW(client_thread.hwnd, WM_UIA_CLIENT_GET_NODE_PROV, (WPARAM)&args, (LPARAM)node);
}
/***********************************************************************
* UiaNodeFromHandle (uiautomationcore.@)
*/
HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode)
static HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags)
{
struct uia_node *node;
HRESULT hr;
TRACE("(%p, %p)\n", hwnd, huianode);
if (!huianode)
if (!out_node)
return E_INVALIDARG;
*huianode = NULL;
*out_node = NULL;
if (!IsWindow(hwnd))
return UIA_E_ELEMENTNOTAVAILABLE;
hr = create_uia_node(&node);
hr = create_uia_node(&node, node_flags);
if (FAILED(hr))
return hr;
@ -2601,11 +2603,21 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode)
return hr;
}
*huianode = (void *)&node->IWineUiaNode_iface;
*out_node = (void *)&node->IWineUiaNode_iface;
return S_OK;
}
/***********************************************************************
* UiaNodeFromHandle (uiautomationcore.@)
*/
HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode)
{
TRACE("(%p, %p)\n", hwnd, huianode);
return create_uia_node_from_hwnd(hwnd, huianode, 0);
}
/***********************************************************************
* UiaGetRootNode (uiautomationcore.@)
*/
@ -2621,8 +2633,15 @@ HRESULT WINAPI UiaGetRootNode(HUIANODE *huianode)
*/
BOOL WINAPI UiaHasServerSideProvider(HWND hwnd)
{
FIXME("(%p): stub\n", hwnd);
return FALSE;
HUIANODE node = NULL;
HRESULT hr;
TRACE("(%p)\n", hwnd);
hr = create_uia_node_from_hwnd(hwnd, &node, NODE_FLAG_NO_PREPARE | NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS);
UiaNodeRelease(node);
return SUCCEEDED(hr);
}
static HRESULT get_focused_uia_node(HUIANODE in_node, HUIANODE *out_node)
@ -3026,6 +3045,9 @@ static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type,
VARTYPE vt;
HRESULT hr;
if (node->ignore_clientside_hwnd_provs)
return S_OK;
if (!(sa = uia_provider_callback(node->hwnd, prov_type)))
return S_OK;

View file

@ -54,6 +54,11 @@ enum uia_node_prov_type {
PROV_TYPE_COUNT,
};
enum uia_node_flags {
NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS = 0x01,
NODE_FLAG_NO_PREPARE = 0x02,
};
struct uia_node {
IWineUiaNode IWineUiaNode_iface;
LONG ref;
@ -65,9 +70,12 @@ struct uia_node {
int creator_prov_idx;
HWND hwnd;
BOOL no_prepare;
BOOL nested_node;
BOOL disconnected;
int creator_prov_type;
BOOL ignore_clientside_hwnd_provs;
struct list prov_thread_list_entry;
struct list node_map_list_entry;
struct uia_provider_thread_map_entry *map;