From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 28 +-- dlls/uiautomationcore/uia_classes.idl | 2 +- dlls/uiautomationcore/uia_client.c | 273 ++++++++++++++------- dlls/uiautomationcore/uia_private.h | 28 ++- dlls/uiautomationcore/uia_provider.c | 4 +- 5 files changed, 231 insertions(+), 104 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 85270ca7f27..54d6fa710b5 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4328,14 +4328,14 @@ static const struct prov_method_sequence get_elem_arr_prop_seq[] = { { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider_child2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child2, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child2, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, { &Provider_child2, PROV_GET_PROPERTY_VALUE }, { 0 } @@ -4972,8 +4972,8 @@ static const struct prov_method_sequence node_from_hwnd2[] = { { &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, METHOD_TODO }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ /* Windows 10+ calls this. */ { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -4987,7 +4987,7 @@ static const struct prov_method_sequence node_from_hwnd3[] = { { &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, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } @@ -5016,7 +5016,7 @@ static const struct prov_method_sequence node_from_hwnd5[] = { { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Only done in Windows 8+. */ { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, @@ -5034,7 +5034,7 @@ static const struct prov_method_sequence node_from_hwnd6[] = { { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Next 4 are only done in Windows 8+. */ { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, @@ -5059,7 +5059,7 @@ static const struct prov_method_sequence node_from_hwnd7[] = { { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ @@ -5077,7 +5077,7 @@ static const struct prov_method_sequence node_from_hwnd8[] = { { &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, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ @@ -5091,7 +5091,7 @@ static const struct prov_method_sequence node_from_hwnd9[] = { { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, /* Only done in Windows 8+. */ { &Provider, FRAG_GET_RUNTIME_ID, METHOD_OPTIONAL }, { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, @@ -5109,7 +5109,7 @@ static const struct prov_method_sequence disconnect_prov1[] = { { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, FRAG_GET_RUNTIME_ID }, { &Provider_child, FRAG_GET_FRAGMENT_ROOT }, { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, @@ -5124,7 +5124,7 @@ static const struct prov_method_sequence disconnect_prov2[] = { { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, FRAG_GET_RUNTIME_ID }, { &Provider, FRAG_GET_FRAGMENT_ROOT }, { 0 } @@ -5137,7 +5137,7 @@ static const struct prov_method_sequence disconnect_prov3[] = { { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, FRAG_GET_RUNTIME_ID }, { 0 } }; @@ -5148,7 +5148,7 @@ static const struct prov_method_sequence disconnect_prov4[] = { { &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, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { 0 } };
diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 2fb0e88086b..5877d14b8e5 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -54,7 +54,7 @@ library UIA_wine_private ] interface IWineUiaNode : IUnknown { - HRESULT get_provider([out, retval]IWineUiaProvider **out_prov); + HRESULT get_provider([in]int idx, [out, retval]IWineUiaProvider **out_prov); HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); HRESULT disconnect(); } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index b8c94b831e6..17dd5ab9b6e 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -314,6 +314,25 @@ static IRawElementProviderSimple *get_provider_hwnd_fragment_root(IRawElementPro return ret; }
+int get_node_provider_type_at_idx(struct uia_node *node, int idx) +{ + int i, prov_idx; + + for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++) + { + if (node->prov[i]) + { + if (prov_idx == idx) + return i; + else + prov_idx++; + } + } + + ERR("Node %p has no provider at idx %d\n", node, idx); + return 0; +} + /* * IWineUiaNode interface. */ @@ -346,22 +365,28 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface) TRACE("%p, refcount %ld\n", node, ref); if (!ref) { - if (node->git_cookie) - { - IGlobalInterfaceTable *git; - HRESULT hr; + int i;
- hr = get_global_interface_table(&git); - if (SUCCEEDED(hr)) + for (i = 0; i < PROV_TYPE_COUNT; i++) + { + if (node->git_cookie[i]) { - hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie); - if (FAILED(hr)) - WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr); + IGlobalInterfaceTable *git; + HRESULT hr; + + hr = get_global_interface_table(&git); + if (SUCCEEDED(hr)) + { + hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie[i]); + if (FAILED(hr)) + WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr); + } } + + if (node->prov[i]) + IWineUiaProvider_Release(node->prov[i]); }
- if (node->prov) - IWineUiaProvider_Release(node->prov); if (!list_empty(&node->prov_thread_list_entry)) uia_provider_thread_remove_node((HUIANODE)iface); if (node->nested_node) @@ -373,17 +398,22 @@ static ULONG WINAPI uia_node_Release(IWineUiaNode *iface) return ref; }
-static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvider **out_prov) +static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, int idx, IWineUiaProvider **out_prov) { struct uia_node *node = impl_from_IWineUiaNode(iface); + int prov_type;
+ TRACE("(%p, %d, %p)\n", iface, idx, out_prov); + + *out_prov = NULL; if (node->disconnected) - { - *out_prov = NULL; return UIA_E_ELEMENTNOTAVAILABLE; - }
- if (node->git_cookie) + if (idx >= node->prov_count) + return E_INVALIDARG; + + prov_type = get_node_provider_type_at_idx(node, idx); + if (node->git_cookie[prov_type]) { IGlobalInterfaceTable *git; IWineUiaProvider *prov; @@ -393,7 +423,7 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvide if (FAILED(hr)) return hr;
- hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, node->git_cookie, + hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, node->git_cookie[prov_type], &IID_IWineUiaProvider, (void **)&prov); if (FAILED(hr)) { @@ -404,8 +434,8 @@ static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, IWineUiaProvide } else { - *out_prov = node->prov; - IWineUiaProvider_AddRef(node->prov); + *out_prov = node->prov[prov_type]; + IWineUiaProvider_AddRef(node->prov[prov_type]); }
return S_OK; @@ -441,6 +471,7 @@ static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *pro static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface) { struct uia_node *node = impl_from_IWineUiaNode(iface); + int prov_type;
TRACE("%p\n", node);
@@ -450,7 +481,9 @@ static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface) return E_FAIL; }
- if (node->git_cookie) + /* Nested nodes can only have one provider. */ + prov_type = get_node_provider_type_at_idx(node, 0); + if (node->git_cookie[prov_type]) { IGlobalInterfaceTable *git; HRESULT hr; @@ -458,16 +491,18 @@ static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface) hr = get_global_interface_table(&git); if (SUCCEEDED(hr)) { - hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie); + hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, node->git_cookie[prov_type]); if (FAILED(hr)) WARN("Failed to get revoke provider interface from Global Interface Table, hr %#lx\n", hr); } - node->git_cookie = 0; + node->git_cookie[prov_type] = 0; }
- IWineUiaProvider_Release(node->prov); - node->prov = NULL; + IWineUiaProvider_Release(node->prov[prov_type]); + node->prov[prov_type] = NULL; + node->disconnected = TRUE; + node->prov_count = 0;
return S_OK; } @@ -489,6 +524,49 @@ static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface) return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface); }
+static BOOL is_nested_node_provider(IWineUiaProvider *iface); +static HRESULT finalize_uia_node(struct uia_node *node) +{ + int i; + + for (i = 0; i < PROV_TYPE_COUNT; i++) + { + enum ProviderOptions prov_opts; + IGlobalInterfaceTable *git; + struct uia_provider *prov; + HRESULT hr; + + /* Only regular providers need to be queried for UseComThreading. */ + if (!node->prov[i] || is_nested_node_provider(node->prov[i])) + continue; + + prov = impl_from_IWineUiaProvider(node->prov[i]); + hr = IRawElementProviderSimple_get_ProviderOptions(prov->elprov, &prov_opts); + if (FAILED(hr)) + continue; + + /* + * If the UseComThreading ProviderOption is specified, all calls to the + * provided IRawElementProviderSimple need to respect the apartment type + * of the thread that creates the HUIANODE. i.e, if it's created in an + * STA, and the HUIANODE is used in an MTA, we need to provide a proxy. + */ + if (prov_opts & ProviderOptions_UseComThreading) + { + hr = get_global_interface_table(&git); + if (FAILED(hr)) + return hr; + + hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&prov->IWineUiaProvider_iface, + &IID_IWineUiaProvider, &node->git_cookie[i]); + if (FAILED(hr)) + return hr; + } + } + + return S_OK; +} + /* * IWineUiaProvider interface. */ @@ -768,55 +846,19 @@ static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_get_prop_val, };
-static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov) +static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, + int prov_type) { - static const int supported_prov_opts = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading; - enum ProviderOptions prov_opts; - struct uia_provider *prov; - HRESULT hr; + struct uia_provider *prov = heap_alloc_zero(sizeof(*prov));
- hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); - if (FAILED(hr)) - return hr; - - if (prov_opts & ~supported_prov_opts) - FIXME("Ignoring unsupported ProviderOption(s) %#x\n", prov_opts & ~supported_prov_opts); - - prov = heap_alloc_zero(sizeof(*prov)); if (!prov) return E_OUTOFMEMORY;
prov->IWineUiaProvider_iface.lpVtbl = &uia_provider_vtbl; prov->elprov = elprov; prov->ref = 1; - node->prov = &prov->IWineUiaProvider_iface; - node->hwnd = get_hwnd_from_provider(elprov); - - /* - * If the UseComThreading ProviderOption is specified, all calls to the - * provided IRawElementProviderSimple need to respect the apartment type - * of the thread that creates the HUIANODE. i.e, if it's created in an - * STA, and the HUIANODE is used in an MTA, we need to provide a proxy. - */ - if (prov_opts & ProviderOptions_UseComThreading) - { - IGlobalInterfaceTable *git; - - hr = get_global_interface_table(&git); - if (FAILED(hr)) - { - heap_free(prov); - return hr; - } - - hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, (IUnknown *)&prov->IWineUiaProvider_iface, - &IID_IWineUiaProvider, &node->git_cookie); - if (FAILED(hr)) - { - heap_free(prov); - return hr; - } - } + node->prov[prov_type] = &prov->IWineUiaProvider_iface; + node->prov_count++;
IRawElementProviderSimple_AddRef(elprov); return S_OK; @@ -827,7 +869,11 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid */ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *huianode) { + static const int unsupported_prov_opts = ProviderOptions_ProviderOwnsSetFocus | ProviderOptions_HasNativeIAccessible | + ProviderOptions_UseClientCoordinates; + enum ProviderOptions prov_opts; struct uia_node *node; + int prov_type; HRESULT hr;
TRACE("(%p, %p)\n", elprov, huianode); @@ -837,25 +883,51 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *
*huianode = NULL;
+ hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); + if (FAILED(hr)) + return hr; + + if (prov_opts & unsupported_prov_opts) + FIXME("Ignoring unsupported ProviderOption(s) %#x\n", prov_opts & unsupported_prov_opts); + + if (prov_opts & ProviderOptions_OverrideProvider) + prov_type = PROV_TYPE_OVERRIDE; + else if (prov_opts & ProviderOptions_NonClientAreaProvider) + prov_type = PROV_TYPE_NONCLIENT; + else if (prov_opts & ProviderOptions_ServerSideProvider) + prov_type = PROV_TYPE_MAIN; + else if (prov_opts & ProviderOptions_ClientSideProvider) + prov_type = PROV_TYPE_HWND; + else + prov_type = PROV_TYPE_MAIN; + node = heap_alloc_zero(sizeof(*node)); if (!node) return E_OUTOFMEMORY;
- hr = create_wine_uia_provider(node, elprov); + node->IWineUiaNode_iface.lpVtbl = &uia_node_vtbl; + node->hwnd = get_hwnd_from_provider(elprov); + list_init(&node->prov_thread_list_entry); + list_init(&node->node_map_list_entry); + node->ref = 1; + + hr = create_wine_uia_provider(node, elprov, prov_type); if (FAILED(hr)) { heap_free(node); return hr; }
- node->IWineUiaNode_iface.lpVtbl = &uia_node_vtbl; - list_init(&node->prov_thread_list_entry); - list_init(&node->node_map_list_entry); - node->ref = 1; + hr = finalize_uia_node(node); + if (FAILED(hr)) + { + IWineUiaNode_Release(&node->IWineUiaNode_iface); + return hr; + }
*huianode = (void *)&node->IWineUiaNode_iface;
- return hr; + return S_OK; }
/* @@ -1121,6 +1193,14 @@ static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_get_prop_val, };
+static BOOL is_nested_node_provider(IWineUiaProvider *iface) +{ + if (iface->lpVtbl == &uia_nested_node_provider_vtbl) + return TRUE; + + return FALSE; +} + static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESULT lr, BOOL unwrap) { @@ -1155,14 +1235,14 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU return E_FAIL; }
- IWineUiaProvider_AddRef(node_data->prov); - provider_iface = node_data->prov; - git_cookie = node_data->git_cookie; - prov_data = impl_from_IWineUiaProvider(node_data->prov); + provider_iface = node_data->prov[get_node_provider_type_at_idx(node_data, 0)]; + git_cookie = 0; + + IWineUiaProvider_AddRef(provider_iface); + prov_data = impl_from_IWineUiaProvider(provider_iface); prov_data->return_nested_node = FALSE;
- node_data->git_cookie = 0; - IWineUiaNode_Release(&node_data->IWineUiaNode_iface); + IWineUiaNode_Release(nested_node); uia_stop_client_thread(); } else @@ -1196,8 +1276,9 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU } }
- node->prov = provider_iface; - node->git_cookie = git_cookie; + node->prov[PROV_TYPE_MAIN] = provider_iface; + node->git_cookie[PROV_TYPE_MAIN] = git_cookie; + node->prov_count++;
return S_OK; } @@ -1225,6 +1306,13 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode) return hr; }
+ hr = finalize_uia_node(node); + if (FAILED(hr)) + { + IWineUiaNode_Release(&node->IWineUiaNode_iface); + return hr; + } + *huianode = (void *)&node->IWineUiaNode_iface;
return hr; @@ -1296,6 +1384,13 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode) return hr; }
+ hr = finalize_uia_node(node); + if (FAILED(hr)) + { + IWineUiaNode_Release(&node->IWineUiaNode_iface); + return hr; + } + *huianode = (void *)&node->IWineUiaNode_iface;
return S_OK; @@ -1321,15 +1416,21 @@ static HRESULT get_prop_val_from_node_provider(struct uia_node *node, const struct uia_prop_info *prop_info, VARIANT *v) { IWineUiaProvider *prov; - HRESULT hr; + HRESULT hr = S_OK; + int i;
- hr = IWineUiaNode_get_provider(&node->IWineUiaNode_iface, &prov); - if (FAILED(hr)) - return hr; + for (i = 0; i < node->prov_count; i++) + { + hr = IWineUiaNode_get_provider(&node->IWineUiaNode_iface, i, &prov); + if (FAILED(hr)) + return hr;
- VariantInit(v); - hr = IWineUiaProvider_get_prop_val(prov, prop_info, v); - IWineUiaProvider_Release(prov); + VariantInit(v); + hr = IWineUiaProvider_get_prop_val(prov, prop_info, v); + IWineUiaProvider_Release(prov); + if (FAILED(hr) || V_VT(v) != VT_EMPTY) + break; + }
return hr; } diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 40589d538be..daa6df63044 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -30,12 +30,35 @@ enum uia_prop_type { PROP_TYPE_SPECIAL, };
+/* + * HUIANODEs that have an associated HWND are able to pull data from up to 4 + * different providers: + * + * - Override providers are used to override values from all other providers. + * - Main providers are the base provider for an HUIANODE. + * - Nonclient providers are used to represent the nonclient area of the HWND. + * - HWND providers are used to represent data from the HWND as a whole, such + * as the bounding box. + * + * When a property is requested from the node, each provider is queried in + * descending order starting with the override provider until either one + * returns a property or there are no more providers to query. + */ +enum uia_node_prov_type { + PROV_TYPE_OVERRIDE, + PROV_TYPE_MAIN, + PROV_TYPE_NONCLIENT, + PROV_TYPE_HWND, + PROV_TYPE_COUNT, +}; + struct uia_node { IWineUiaNode IWineUiaNode_iface; LONG ref;
- IWineUiaProvider *prov; - DWORD git_cookie; + IWineUiaProvider *prov[PROV_TYPE_COUNT]; + DWORD git_cookie[PROV_TYPE_COUNT]; + int prov_count;
HWND hwnd; BOOL nested_node; @@ -65,6 +88,7 @@ static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider *
/* uia_client.c */ int uia_compare_runtime_ids(SAFEARRAY *sa1, SAFEARRAY *sa2) DECLSPEC_HIDDEN; +int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN;
/* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 44850a55b05..99fdd07f40c 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1231,10 +1231,12 @@ exit: static HRESULT uia_provider_thread_add_node(HUIANODE node) { struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node); - struct uia_provider *prov_data = impl_from_IWineUiaProvider(node_data->prov); + int prov_type = get_node_provider_type_at_idx(node_data, 0); + struct uia_provider *prov_data; SAFEARRAY *sa; HRESULT hr;
+ prov_data = impl_from_IWineUiaProvider(node_data->prov[prov_type]); node_data->nested_node = prov_data->return_nested_node = TRUE; hr = UiaGetRuntimeId(node, &sa); if (FAILED(hr))
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 8 +-- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 63 +++++++++++++++++++++- 3 files changed, 66 insertions(+), 6 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 54d6fa710b5..604e488601f 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4988,7 +4988,7 @@ static const struct prov_method_sequence node_from_hwnd3[] = { { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } }; @@ -5040,7 +5040,7 @@ static const struct prov_method_sequence node_from_hwnd6[] = { { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, /* Next two are only done on Win10v1809+. */ { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, @@ -5060,7 +5060,7 @@ static const struct prov_method_sequence node_from_hwnd7[] = { { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, - { &Provider_child, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, @@ -5078,7 +5078,7 @@ static const struct prov_method_sequence node_from_hwnd8[] = { { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ { 0 } diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 5877d14b8e5..4540613bba2 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -44,6 +44,7 @@ library UIA_wine_private interface IWineUiaProvider : IUnknown { HRESULT get_prop_val([in]const struct uia_prop_info *prop_info, [out, retval]VARIANT *ret_val); + HRESULT get_prov_opts([out, retval]int *out_opts); }
[ diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 17dd5ab9b6e..1dc509a7227 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -333,6 +333,22 @@ int get_node_provider_type_at_idx(struct uia_node *node, int idx) return 0; }
+static HRESULT get_prov_opts_from_node_provider(IWineUiaNode *node, int idx, int *out_opts) +{ + IWineUiaProvider *prov; + HRESULT hr; + + *out_opts = 0; + hr = IWineUiaNode_get_provider(node, idx, &prov); + if (FAILED(hr)) + return hr; + + hr = IWineUiaProvider_get_prov_opts(prov, out_opts); + IWineUiaProvider_Release(prov); + + return hr; +} + /* * IWineUiaNode interface. */ @@ -839,11 +855,28 @@ static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface, return S_OK; }
+static HRESULT WINAPI uia_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts) +{ + struct uia_provider *prov = impl_from_IWineUiaProvider(iface); + enum ProviderOptions prov_opts; + HRESULT hr; + + TRACE("%p, %p\n", iface, out_opts); + + *out_opts = 0; + hr = IRawElementProviderSimple_get_ProviderOptions(prov->elprov, &prov_opts); + if (SUCCEEDED(hr)) + *out_opts = prov_opts; + + return S_OK; +} + static const IWineUiaProviderVtbl uia_provider_vtbl = { uia_provider_QueryInterface, uia_provider_AddRef, uia_provider_Release, uia_provider_get_prop_val, + uia_provider_get_prov_opts, };
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, @@ -1186,11 +1219,21 @@ static HRESULT WINAPI uia_nested_node_provider_get_prop_val(IWineUiaProvider *if return S_OK; }
+static HRESULT WINAPI uia_nested_node_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts) +{ + struct uia_nested_node_provider *prov = impl_from_nested_node_IWineUiaProvider(iface); + + TRACE("%p, %p\n", iface, out_opts); + + return get_prov_opts_from_node_provider(prov->nested_node, 0, out_opts); +} + static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = { uia_nested_node_provider_QueryInterface, uia_nested_node_provider_AddRef, uia_nested_node_provider_Release, uia_nested_node_provider_get_prop_val, + uia_nested_node_provider_get_prov_opts, };
static BOOL is_nested_node_provider(IWineUiaProvider *iface) @@ -1208,6 +1251,7 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU struct uia_nested_node_provider *prov; IGlobalInterfaceTable *git; IWineUiaNode *nested_node; + int prov_opts, prov_type; DWORD git_cookie; HRESULT hr;
@@ -1218,6 +1262,21 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU return hr; }
+ hr = get_prov_opts_from_node_provider(nested_node, 0, &prov_opts); + if (FAILED(hr)) + { + WARN("Failed to get provider options for node %p with hr %#lx\n", nested_node, hr); + IWineUiaNode_Release(nested_node); + uia_stop_client_thread(); + return hr; + } + + /* Nested nodes can only serve as override or main providers. */ + if (prov_opts & ProviderOptions_OverrideProvider) + prov_type = PROV_TYPE_OVERRIDE; + else + prov_type = PROV_TYPE_MAIN; + /* * If we're retrieving a node from an HWND that belongs to the same thread * as the client making the request, return a normal provider instead of a @@ -1276,8 +1335,8 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU } }
- node->prov[PROV_TYPE_MAIN] = provider_iface; - node->git_cookie[PROV_TYPE_MAIN] = git_cookie; + node->prov[prov_type] = provider_iface; + node->git_cookie[prov_type] = git_cookie; node->prov_count++;
return S_OK;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 34 +++++++++--------- dlls/uiautomationcore/uia_client.c | 42 +++++++++++++++------- dlls/uiautomationcore/uia_private.h | 2 ++ dlls/uiautomationcore/uia_provider.c | 4 +-- 4 files changed, 51 insertions(+), 31 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 604e488601f..d8271ea048c 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -3843,10 +3843,10 @@ static const struct prov_method_sequence node_from_prov5[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ /* These three are only done on Win10v1507 and below. */ { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, @@ -3868,13 +3868,13 @@ static const struct prov_method_sequence node_from_prov6[] = { /* Win10v1507 and below call this. */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Only called on Windows versions past Win10v1507. */ { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider2, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ @@ -3893,13 +3893,13 @@ static const struct prov_method_sequence node_from_prov7[] = { /* Win10v1507 and below call this. */ { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Win10v1507 and below call this. */ { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, - { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS }, /* Only called on Windows versions past Win10v1507. */ { &Provider_child, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, { &Provider2, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ @@ -4136,7 +4136,7 @@ static void test_UiaNodeFromProvider(void) hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &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(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); @@ -4178,7 +4178,7 @@ static void test_UiaNodeFromProvider(void) SET_EXPECT(winproc_GETOBJECT_CLIENT); hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
/* Win10v1507 and below hold a reference to the root provider for the HWND */ @@ -4227,7 +4227,7 @@ static void test_UiaNodeFromProvider(void) SET_EXPECT(winproc_GETOBJECT_CLIENT); hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); @@ -4242,7 +4242,7 @@ static void test_UiaNodeFromProvider(void) } ok_method_sequence(node_from_prov6, "node_from_prov6");
- todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); + ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
ok(!!node, "node == NULL\n"); @@ -4261,7 +4261,7 @@ static void test_UiaNodeFromProvider(void) SET_EXPECT(winproc_GETOBJECT_CLIENT); hr = UiaNodeFromProvider(&Provider_child.IRawElementProviderSimple_iface, &node); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); @@ -4276,7 +4276,7 @@ static void test_UiaNodeFromProvider(void) } ok_method_sequence(node_from_prov7, "node_from_prov7");
- todo_wine ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); + ok(Provider2.ref == 2, "Unexpected refcnt %ld\n", Provider2.ref); ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
ok(!!node, "node == NULL\n"); @@ -4839,7 +4839,7 @@ static void test_UiaGetRuntimeId(void) SET_EXPECT(winproc_GETOBJECT_CLIENT); hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
VariantInit(&v); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 1dc509a7227..40688dc344d 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -718,7 +718,7 @@ static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, if (FAILED(hr)) goto exit;
- hr = UiaNodeFromProvider(elprov, &node); + hr = create_uia_node_from_elprov(elprov, &node, !prov->return_nested_node); IRawElementProviderSimple_Release(elprov); if (SUCCEEDED(hr)) { @@ -897,10 +897,9 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid return S_OK; }
-/*********************************************************************** - * UiaNodeFromProvider (uiautomationcore.@) - */ -HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *huianode) +static HRESULT uia_get_provider_from_hwnd(struct uia_node *node); +HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, + BOOL get_hwnd_providers) { static const int unsupported_prov_opts = ProviderOptions_ProviderOwnsSetFocus | ProviderOptions_HasNativeIAccessible | ProviderOptions_UseClientCoordinates; @@ -909,12 +908,7 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE * int prov_type; HRESULT hr;
- TRACE("(%p, %p)\n", elprov, huianode); - - if (!elprov || !huianode) - return E_INVALIDARG; - - *huianode = NULL; + *out_node = NULL;
hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts); if (FAILED(hr)) @@ -951,6 +945,9 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE * return hr; }
+ if (node->hwnd && get_hwnd_providers) + uia_get_provider_from_hwnd(node); + hr = finalize_uia_node(node); if (FAILED(hr)) { @@ -958,11 +955,24 @@ HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE * return hr; }
- *huianode = (void *)&node->IWineUiaNode_iface; + *out_node = (void *)&node->IWineUiaNode_iface;
return S_OK; }
+/*********************************************************************** + * UiaNodeFromProvider (uiautomationcore.@) + */ +HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *huianode) +{ + TRACE("(%p, %p)\n", elprov, huianode); + + if (!elprov || !huianode) + return E_INVALIDARG; + + return create_uia_node_from_elprov(elprov, huianode, TRUE); +} + /* * UI Automation client thread functions. */ @@ -1277,6 +1287,14 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU else prov_type = PROV_TYPE_MAIN;
+ if (node->prov[prov_type]) + { + TRACE("Already have a provider of type %d for this node.\n", prov_type); + IWineUiaNode_Release(nested_node); + uia_stop_client_thread(); + return S_OK; + } + /* * If we're retrieving a node from an HWND that belongs to the same thread * as the client making the request, return a normal provider instead of a diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index daa6df63044..697a1d6aa4e 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -89,6 +89,8 @@ static inline struct uia_provider *impl_from_IWineUiaProvider(IWineUiaProvider * /* uia_client.c */ int uia_compare_runtime_ids(SAFEARRAY *sa1, SAFEARRAY *sa2) DECLSPEC_HIDDEN; int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN; +HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, + BOOL get_hwnd_providers) DECLSPEC_HIDDEN;
/* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 99fdd07f40c..e88d4be9565 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1464,7 +1464,7 @@ LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wparam, return 0; }
- hr = UiaNodeFromProvider(elprov, &node); + hr = create_uia_node_from_elprov(elprov, &node, FALSE); if (FAILED(hr)) { WARN("Failed to create HUIANODE with hr %#lx\n", hr); @@ -1485,7 +1485,7 @@ HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov)
TRACE("(%p)\n", elprov);
- hr = UiaNodeFromProvider(elprov, &node); + hr = create_uia_node_from_elprov(elprov, &node, FALSE); if (FAILED(hr)) return hr;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 10 ++++---- dlls/uiautomationcore/uia_classes.idl | 1 + dlls/uiautomationcore/uia_client.c | 28 ++++++++++++++++++++++ 3 files changed, 34 insertions(+), 5 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index d8271ea048c..c9ed575c1ae 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -5061,12 +5061,12 @@ static const struct prov_method_sequence node_from_hwnd7[] = { { &Provider_child, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, - { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } }; @@ -5352,7 +5352,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) SET_EXPECT(winproc_GETOBJECT_CLIENT); hr = UiaGetPropertyValue(node, UIA_LabeledByPropertyId, &v); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref);
diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index 4540613bba2..a240534222a 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -58,5 +58,6 @@ library UIA_wine_private HRESULT get_provider([in]int idx, [out, retval]IWineUiaProvider **out_prov); HRESULT get_prop_val([in]const GUID *prop_guid, [out, retval]VARIANT *ret_val); HRESULT disconnect(); + HRESULT get_hwnd([out, retval]ULONG *out_hwnd); } } diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 40688dc344d..30d7e09a634 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -523,6 +523,17 @@ static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface) return S_OK; }
+static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd) +{ + struct uia_node *node = impl_from_IWineUiaNode(iface); + + TRACE("%p, %p\n", node, out_hwnd); + + *out_hwnd = HandleToUlong(node->hwnd); + + return S_OK; +} + static const IWineUiaNodeVtbl uia_node_vtbl = { uia_node_QueryInterface, uia_node_AddRef, @@ -530,6 +541,7 @@ static const IWineUiaNodeVtbl uia_node_vtbl = { uia_node_get_provider, uia_node_get_prop_val, uia_node_disconnect, + uia_node_get_hwnd, };
static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface) @@ -1351,6 +1363,15 @@ static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESU IWineUiaProvider_Release(&prov->IWineUiaProvider_iface); return hr; } + + if (!node->hwnd) + { + ULONG hwnd; + + hr = IWineUiaNode_get_hwnd(nested_node, &hwnd); + if (SUCCEEDED(hr)) + node->hwnd = UlongToHandle(hwnd); + } }
node->prov[prov_type] = provider_iface; @@ -1383,6 +1404,13 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode) return hr; }
+ if (node->hwnd) + { + hr = uia_get_provider_from_hwnd(node); + if (FAILED(hr)) + WARN("uia_get_provider_from_hwnd failed with hr %#lx\n", hr); + } + hr = finalize_uia_node(node); if (FAILED(hr)) {
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=124962
Your paranoid android.
=== debian11 (build log) ===
Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24664. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24664. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24664.
Might be good to call finalize_uia_node something else, I keep thinking it's going to free things because that's what finalizers do.
On Sun Oct 16 15:49:19 2022 +0000, Esme Povirk wrote:
Might be good to call finalize_uia_node something else, I keep thinking it's going to free things because that's what finalizers do.
Hm... okay. Any suggestions on a better word than `finalize()`? The function gets used later on to do other things as well. It's basically a function that gets ran once all possible providers have been added to a node. I have thought of `close` maybe, but without there being a corresponding `open` it seems weird.
On Sun Oct 16 15:49:19 2022 +0000, Connor McAdams wrote:
Hm... okay. Any suggestions on a better word than `finalize()`? The function gets used later on to do other things as well. It's basically a function that gets ran once all possible providers have been added to a node. I have thought of `close` maybe, but without there being a corresponding `open` it seems weird.
Close would also make me expect it to free/release things.
Prepare, maybe?