diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a733e183312..fd1f5d0414b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -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"); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index b1a21de3a17..57d1ca812f7 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -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; diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 253eacbc4e7..e8bb4845189 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -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;