From: Connor McAdams cmcadams@codeweavers.com
Windows versions 10v1507 and below classify a provider as an HWND provider if it returns a value for UIA_NativeWindowHandle. By ignoring this property, we get more consistent behavior in tests between all Windows versions.
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 84 ++++++++-------------- 1 file changed, 30 insertions(+), 54 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index c9ed575c1ae..1aa7b2353ba 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1108,6 +1108,7 @@ static struct Provider DWORD expected_tid; int runtime_id[2]; DWORD last_call_tid; + BOOL ignore_hwnd_prop; } Provider, Provider2, Provider_child, Provider_child2;
static const WCHAR *uia_bstr_prop_str = L"uia-string"; @@ -1555,7 +1556,7 @@ HRESULT WINAPI ProviderSimple_GetPropertyValue(IRawElementProviderSimple *iface, V_VT(ret_val) = VT_R8; V_R8(ret_val) = uia_r8_prop_val; } - else + else if (!This->ignore_hwnd_prop) { V_VT(ret_val) = VT_I4; V_I4(ret_val) = HandleToULong(This->hwnd); @@ -4133,6 +4134,7 @@ static void test_UiaNodeFromProvider(void) SET_EXPECT(winproc_GETOBJECT_UiaRoot); /* Win10v1507 and below send this, Windows 7 sends it twice. */ SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); + Provider.ignore_hwnd_prop = TRUE; 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); @@ -4144,33 +4146,26 @@ static void test_UiaNodeFromProvider(void) if (SUCCEEDED(hr)) { check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); - - /* Newer versions of Windows have "Hwnd(parent link):" */ - if (get_provider_desc(V_BSTR(&v), L"Hwnd(parent link):", NULL)) - { - check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); - check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); - } - else - { - check_node_provider_desc(V_BSTR(&v), L"Annotation", NULL, TRUE); - check_node_provider_desc(V_BSTR(&v), L"Main", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE); - } + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); VariantClear(&v); }
+ Provider.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_prov4, "node_from_prov4");
ok(!!node, "node == NULL\n"); ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
- /* Return Provider2 in response to WM_GETOBJECT. */ + /* + * Provider is our main provider, since Provider2 is also a main, it won't + * get added. + */ Provider.hwnd = Provider2.hwnd = hwnd; Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider; + Provider.ignore_hwnd_prop = Provider2.ignore_hwnd_prop = TRUE; prov_root = &Provider2.IRawElementProviderSimple_iface; node = (void *)0xdeadbeef; SET_EXPECT(winproc_GETOBJECT_UiaRoot); @@ -4182,7 +4177,6 @@ static void test_UiaNodeFromProvider(void) called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
/* Win10v1507 and below hold a reference to the root provider for the HWND */ - ok(broken(Provider2.ref == 2) || Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); ok(!!node, "node == NULL\n");
@@ -4191,23 +4185,13 @@ static void test_UiaNodeFromProvider(void) if (SUCCEEDED(hr)) { check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); - - /* Newer versions of Windows have "Hwnd(parent link):" */ - if (get_provider_desc(V_BSTR(&v), L"Hwnd(parent link):", NULL)) - { - check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); - check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); - } - else - { - check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider2", TRUE); - check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE); - } + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); VariantClear(&v); }
+ Provider.ignore_hwnd_prop = Provider2.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_prov5, "node_from_prov5");
ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); @@ -4215,8 +4199,8 @@ static void test_UiaNodeFromProvider(void) ok(Provider2.ref == 1, "Unexpected refcnt %ld\n", Provider2.ref);
/* - * Windows 10 newer than v1507 only matches older behavior if - * Provider is a ClientSideProvider. + * Provider is classified as an Hwnd provider, Provider2 will become our + * Main provider since we don't have one already. */ Provider.prov_opts = ProviderOptions_ClientSideProvider; Provider2.prov_opts = ProviderOptions_ServerSideProvider; @@ -5181,11 +5165,7 @@ static void test_UiaNodeFromHandle_client_proc(void)
ok(get_nested_provider_desc(V_BSTR(&v), L"Main", FALSE, buf), "Failed to get nested provider description\n"); check_node_provider_desc_prefix(buf, pid, hwnd); - /* Win10v1507 and below have the nested provider as 'Hwnd'. */ - if (get_provider_desc(buf, L"Hwnd(parent link):", NULL)) - check_node_provider_desc(buf, L"Hwnd", L"Provider", TRUE); - else - check_node_provider_desc(buf, L"Main", L"Provider", TRUE); + check_node_provider_desc(buf, L"Main", L"Provider", TRUE);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); @@ -5243,6 +5223,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Provider.runtime_id[0] = Provider.runtime_id[1] = 0; Provider.frag_root = NULL; Provider.prov_opts = ProviderOptions_ServerSideProvider; + Provider.ignore_hwnd_prop = TRUE; hr = UiaNodeFromHandle(hwnd, &node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); @@ -5257,11 +5238,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
ok(get_nested_provider_desc(V_BSTR(&v), L"Main", FALSE, buf), "Failed to get nested provider description\n"); check_node_provider_desc_prefix(buf, GetCurrentProcessId(), hwnd); - /* Win10v1507 and below have the nested provider as 'Hwnd'. */ - if (get_provider_desc(buf, L"Hwnd(parent link):", NULL)) - check_node_provider_desc(buf, L"Hwnd", L"Provider", TRUE); - else - check_node_provider_desc(buf, L"Main", L"Provider", TRUE); + check_node_provider_desc(buf, L"Main", L"Provider", TRUE);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); @@ -5269,6 +5246,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) VariantClear(&v); }
+ Provider.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_hwnd3, "node_from_hwnd3");
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); @@ -5350,6 +5328,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) SET_EXPECT(winproc_GETOBJECT_UiaRoot); /* Only sent on Win7. */ SET_EXPECT(winproc_GETOBJECT_CLIENT); + Provider_child.ignore_hwnd_prop = TRUE; hr = UiaGetPropertyValue(node, UIA_LabeledByPropertyId, &v); ok(hr == S_OK, "Unexpected hr %#lx\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); @@ -5366,11 +5345,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
ok(get_nested_provider_desc(V_BSTR(&v), L"Main", TRUE, buf), "Failed to get nested provider description\n"); check_node_provider_desc_prefix(buf, GetCurrentProcessId(), hwnd); - /* Win10v1507 and below have the nested provider as 'Hwnd'. */ - if (get_provider_desc(buf, L"Hwnd(parent link):", NULL)) - check_node_provider_desc(buf, L"Hwnd", L"Provider_child", TRUE); - else - check_node_provider_desc(buf, L"Main", L"Provider_child", TRUE); + check_node_provider_desc(buf, L"Main", L"Provider_child", TRUE);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); @@ -5378,6 +5353,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) VariantClear(&v); }
+ Provider_child.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_hwnd7, "node_from_hwnd7"); UiaNodeRelease(node2);
@@ -5406,6 +5382,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Provider.hwnd = hwnd; Provider.runtime_id[0] = Provider.runtime_id[1] = 0; Provider.frag_root = NULL; + Provider.ignore_hwnd_prop = TRUE; Provider.prov_opts = ProviderOptions_ServerSideProvider; hr = UiaNodeFromHandle(hwnd, &node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); @@ -5420,11 +5397,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
ok(get_nested_provider_desc(V_BSTR(&v), L"Main", FALSE, buf), "Failed to get nested provider description\n"); check_node_provider_desc_prefix(buf, GetCurrentProcessId(), hwnd); - /* Win10v1507 and below have the nested provider as 'Hwnd'. */ - if (get_provider_desc(buf, L"Hwnd(parent link):", NULL)) - check_node_provider_desc(buf, L"Hwnd", L"Provider", TRUE); - else - check_node_provider_desc(buf, L"Main", L"Provider", TRUE); + check_node_provider_desc(buf, L"Main", L"Provider", TRUE);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); @@ -5432,6 +5405,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) VariantClear(&v); }
+ Provider.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_hwnd3, "node_from_hwnd3");
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); @@ -5817,6 +5791,7 @@ static void test_UiaNodeFromHandle(const char *name) /* Test behavior from separate process. */ Provider.prov_opts = ProviderOptions_ServerSideProvider; Provider.hwnd = hwnd; + Provider.ignore_hwnd_prop = TRUE; prov_root = &Provider.IRawElementProviderSimple_iface; sprintf(cmdline, ""%s" uiautomation UiaNodeFromHandle_client_proc", name); memset(&startup, 0, sizeof(startup)); @@ -5844,6 +5819,7 @@ static void test_UiaNodeFromHandle(const char *name) CloseHandle(proc.hProcess); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; + Provider.ignore_hwnd_prop = FALSE; ok_method_sequence(node_from_hwnd8, "node_from_hwnd8");
CoUninitialize();
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 845 +++++++++++++++++++++ dlls/uiautomationcore/uia_client.c | 149 +++- dlls/uiautomationcore/uia_main.c | 5 - 3 files changed, 987 insertions(+), 12 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1aa7b2353ba..62826430347 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -68,7 +68,12 @@ static HRESULT (WINAPI *pUiaDisconnectProvider)(IRawElementProviderSimple *); #define UIA_RUNTIME_ID_PREFIX 42
DEFINE_EXPECT(winproc_GETOBJECT_CLIENT); +DEFINE_EXPECT(prov_callback_base_hwnd); +DEFINE_EXPECT(prov_callback_nonclient); +DEFINE_EXPECT(prov_callback_proxy); +DEFINE_EXPECT(prov_callback_parent_proxy); DEFINE_EXPECT(winproc_GETOBJECT_UiaRoot); +DEFINE_EXPECT(child_winproc_GETOBJECT_UiaRoot); DEFINE_EXPECT(Accessible_accNavigate); DEFINE_EXPECT(Accessible_get_accParent); DEFINE_EXPECT(Accessible_get_accChildCount); @@ -1097,6 +1102,7 @@ static struct Provider IRawElementProviderSimple IRawElementProviderSimple_iface; IRawElementProviderFragment IRawElementProviderFragment_iface; IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface; + IRawElementProviderHwndOverride IRawElementProviderHwndOverride_iface; LONG ref;
const char *prov_name; @@ -1109,7 +1115,9 @@ static struct Provider int runtime_id[2]; DWORD last_call_tid; BOOL ignore_hwnd_prop; + HWND override_hwnd; } Provider, Provider2, Provider_child, Provider_child2; +static struct Provider Provider_hwnd, Provider_nc, Provider_proxy, Provider_proxy2, Provider_override;
static const WCHAR *uia_bstr_prop_str = L"uia-string"; static const ULONG uia_i4_prop_val = 0xdeadbeef; @@ -1167,6 +1175,7 @@ enum { FRAG_NAVIGATE, FRAG_GET_RUNTIME_ID, FRAG_GET_FRAGMENT_ROOT, + HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, };
static const char *prov_method_str[] = { @@ -1176,6 +1185,7 @@ static const char *prov_method_str[] = { "Navigate", "GetRuntimeId", "get_FragmentRoot", + "GetOverrideProviderForHwnd", };
static const char *get_prov_method_str(int method) @@ -1491,6 +1501,8 @@ HRESULT WINAPI ProviderSimple_QueryInterface(IRawElementProviderSimple *iface, R *ppv = &This->IRawElementProviderFragment_iface; else if (IsEqualIID(riid, &IID_IRawElementProviderFragmentRoot)) *ppv = &This->IRawElementProviderFragmentRoot_iface; + else if (IsEqualIID(riid, &IID_IRawElementProviderHwndOverride)) + *ppv = &This->IRawElementProviderHwndOverride_iface; else return E_NOINTERFACE;
@@ -1924,11 +1936,60 @@ static const IRawElementProviderFragmentRootVtbl ProviderFragmentRootVtbl = { ProviderFragmentRoot_GetFocus, };
+static inline struct Provider *impl_from_ProviderHwndOverride(IRawElementProviderHwndOverride *iface) +{ + return CONTAINING_RECORD(iface, struct Provider, IRawElementProviderHwndOverride_iface); +} + +static HRESULT WINAPI ProviderHwndOverride_QueryInterface(IRawElementProviderHwndOverride *iface, REFIID riid, + void **ppv) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_QueryInterface(&Provider->IRawElementProviderSimple_iface, riid, ppv); +} + +static ULONG WINAPI ProviderHwndOverride_AddRef(IRawElementProviderHwndOverride *iface) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_AddRef(&Provider->IRawElementProviderSimple_iface); +} + +static ULONG WINAPI ProviderHwndOverride_Release(IRawElementProviderHwndOverride *iface) +{ + struct Provider *Provider = impl_from_ProviderHwndOverride(iface); + return IRawElementProviderSimple_Release(&Provider->IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI ProviderHwndOverride_GetOverrideProviderForHwnd(IRawElementProviderHwndOverride *iface, + HWND hwnd, IRawElementProviderSimple **ret_val) +{ + struct Provider *This = impl_from_ProviderHwndOverride(iface); + + add_method_call(This, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER); + + *ret_val = NULL; + if (This->override_hwnd == hwnd) + { + return IRawElementProviderSimple_QueryInterface(&Provider_override.IRawElementProviderSimple_iface, + &IID_IRawElementProviderSimple, (void **)ret_val); + } + + return S_OK; +} + +static const IRawElementProviderHwndOverrideVtbl ProviderHwndOverrideVtbl = { + ProviderHwndOverride_QueryInterface, + ProviderHwndOverride_AddRef, + ProviderHwndOverride_Release, + ProviderHwndOverride_GetOverrideProviderForHwnd, +}; + static struct Provider Provider = { { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider", NULL, NULL, @@ -1940,6 +2001,7 @@ static struct Provider Provider2 = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider2", NULL, NULL, @@ -1951,6 +2013,7 @@ static struct Provider Provider_child = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider_child", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, @@ -1962,12 +2025,77 @@ static struct Provider Provider_child2 = { &ProviderSimpleVtbl }, { &ProviderFragmentVtbl }, { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, 1, "Provider_child2", &Provider.IRawElementProviderFragment_iface, &Provider.IRawElementProviderFragmentRoot_iface, ProviderOptions_ServerSideProvider, 0, 0, };
+static struct Provider Provider_hwnd = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_hwnd", + NULL, NULL, + ProviderOptions_ClientSideProvider, 0, 0, +}; + +static struct Provider Provider_nc = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_nc", + NULL, NULL, + ProviderOptions_ClientSideProvider | ProviderOptions_NonClientAreaProvider, + 0, 0, +}; + +static struct Provider Provider_proxy = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_proxy", + NULL, NULL, + ProviderOptions_ClientSideProvider, + 0, 0, +}; + +static struct Provider Provider_proxy2 = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_proxy2", + NULL, NULL, + ProviderOptions_ClientSideProvider, + 0, 0, +}; + +static struct Provider Provider_override = +{ + { &ProviderSimpleVtbl }, + { &ProviderFragmentVtbl }, + { &ProviderFragmentRootVtbl }, + { &ProviderHwndOverrideVtbl }, + 1, + "Provider_override", + NULL, NULL, + ProviderOptions_ServerSideProvider | ProviderOptions_OverrideProvider, + 0, 0, +}; + static IAccessible *acc_client; static IRawElementProviderSimple *prov_root; static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) @@ -2001,6 +2129,30 @@ static LRESULT WINAPI test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPAR return DefWindowProcA(hwnd, message, wParam, lParam); }
+static IRawElementProviderSimple *child_win_prov_root; +static LRESULT WINAPI child_test_wnd_proc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) + { + case WM_GETOBJECT: + if (lParam == UiaRootObjectId) + { + CHECK_EXPECT(child_winproc_GETOBJECT_UiaRoot); + if (child_win_prov_root) + return UiaReturnRawElementProvider(hwnd, wParam, lParam, child_win_prov_root); + + break; + } + + break; + + default: + break; + } + + return DefWindowProcA(hwnd, message, wParam, lParam); +} + static void test_UiaHostProviderFromHwnd(void) { IRawElementProviderSimple *p, *p2; @@ -5829,6 +5981,696 @@ static void test_UiaNodeFromHandle(const char *name) prov_root = NULL; }
+static const struct prov_method_sequence reg_prov_cb1[] = { + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb2[] = { + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10+. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb3[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb4[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These four only done on Win10+. */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb5[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb6[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb7[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb8[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb9[] = { + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_proxy, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE }, /* UIA_ControlTypePropertyId */ + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win7. */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb10[] = { + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider_override, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_proxy, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These four only done on Win10+. */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb11[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &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 }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb12[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &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 }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_TODO }, + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static const struct prov_method_sequence reg_prov_cb13[] = { + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + /* Win10v1507 and below call this. */ + { &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 }, + { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + /* Win10v1507 and below call this. */ + { &Provider2, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider2, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_TODO }, + { &Provider2, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider2, PROV_GET_PROVIDER_OPTIONS, METHOD_TODO }, + { &Provider2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + /* Provider override only retrieved successfully on Win10v1809+ */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_proxy2, HWND_OVERRIDE_GET_OVERRIDE_PROVIDER, METHOD_OPTIONAL }, /* Only done on Win10v1507 and below. */ + /* These two are only done on Win10v1809+. */ + { &Provider_hwnd, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + /* Only done on Win10v1809+. */ + { &Provider_override, FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ + { &Provider, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_nc, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_hwnd, FRAG_NAVIGATE, METHOD_TODO }, /* NavigateDirection_Parent */ + { &Provider_override, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win10v1809+ */ + /* These three only done on Win10+. */ + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_nc, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider_hwnd, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + /* Only done on Win10v1809+. */ + { &Provider_override, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_nc, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { &Provider_hwnd, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ + { 0 } +}; + +static IRawElementProviderSimple *base_hwnd_prov, *proxy_prov, *parent_proxy_prov, *nc_prov; +static SAFEARRAY WINAPI *test_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) +{ + IRawElementProviderSimple *elprov = NULL; + + switch (prov_type) + { + case ProviderType_BaseHwnd: + CHECK_EXPECT(prov_callback_base_hwnd); + elprov = base_hwnd_prov; + break; + + case ProviderType_Proxy: + if (Provider_proxy.hwnd == hwnd) + { + CHECK_EXPECT(prov_callback_proxy); + elprov = proxy_prov; + } + else if (hwnd == GetParent(Provider_proxy.hwnd)) + { + CHECK_EXPECT(prov_callback_parent_proxy); + elprov = parent_proxy_prov; + } + break; + + case ProviderType_NonClientArea: + CHECK_EXPECT(prov_callback_nonclient); + elprov = nc_prov; + break; + + default: + break; + } + + if (elprov) + { + SAFEARRAY *sa; + LONG idx = 0; + + sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1); + if (sa) + SafeArrayPutElement(sa, &idx, (void *)elprov); + + return sa; + } + + return NULL; +} + +static void test_UiaRegisterProviderCallback(void) +{ + HWND hwnd, hwnd2; + WNDCLASSA cls; + HUIANODE node; + HRESULT hr; + VARIANT v; + + cls.style = 0; + cls.lpfnWndProc = test_wnd_proc; + cls.cbClsExtra = 0; + cls.cbWndExtra = 0; + cls.hInstance = GetModuleHandleA(NULL); + cls.hIcon = 0; + cls.hCursor = NULL; + cls.hbrBackground = NULL; + cls.lpszMenuName = NULL; + cls.lpszClassName = "UiaRegisterProviderCallback class"; + + RegisterClassA(&cls); + + cls.lpfnWndProc = child_test_wnd_proc; + cls.lpszClassName = "UiaRegisterProviderCallback child class"; + RegisterClassA(&cls); + + hwnd = CreateWindowA("UiaRegisterProviderCallback class", "Test window", WS_OVERLAPPEDWINDOW, + 0, 0, 100, 100, NULL, NULL, NULL, NULL); + + hwnd2 = CreateWindowA("UiaRegisterProviderCallback child class", "Test child window", WS_CHILD, + 0, 0, 100, 100, hwnd, NULL, NULL, NULL); + + UiaRegisterProviderCallback(test_uia_provider_callback); + + /* No providers returned by UiaRootObjectId or the provider callback. */ + Provider_proxy.hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + /* Windows 7 returns S_OK with a NULL HUIANODE. */ + ok(hr == E_FAIL || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr); + ok(!node, "node != NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + /* Return only nonclient proxy provider. */ + base_hwnd_prov = proxy_prov = parent_proxy_prov = NULL; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(!!node, "node == NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", TRUE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb1, "reg_prov_cb1"); + + UiaNodeRelease(node); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + + /* Return only base_hwnd provider. */ + nc_prov = proxy_prov = parent_proxy_prov = NULL; + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(!!node, "node == NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", TRUE); + VariantClear(&v); + } + + ok_method_sequence(reg_prov_cb2, "reg_prov_cb2"); + + UiaNodeRelease(node); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + + /* Return providers for all ProviderTypes. */ + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface; + parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + Provider_proxy.hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!node, "node == NULL\n"); + ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + 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(reg_prov_cb3, "reg_prov_cb3"); + + UiaNodeRelease(node); + ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + + /* Return an override provider from Provider_proxy2. */ + base_hwnd_prov = &Provider_hwnd.IRawElementProviderSimple_iface; + proxy_prov = &Provider_proxy.IRawElementProviderSimple_iface; + parent_proxy_prov = &Provider_proxy2.IRawElementProviderSimple_iface; + nc_prov = &Provider_nc.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = hwnd2; + child_win_prov_root = prov_root = NULL; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!node, "node == NULL\n"); + ok(Provider_proxy.ref == 2, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_proxy2.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy2.ref); + ok(Provider_nc.ref == 2, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 2, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + todo_wine ok(Provider_override.ref == 2, "Unexpected refcnt %ld\n", Provider_override.ref); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider_proxy", FALSE); + 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(reg_prov_cb4, "reg_prov_cb4"); + + /* + * Test the order that Providers are queried for properties. The order is: + * Override provider. + * Main provider. + * Nonclient provider. + * Hwnd provider. + * + * UI Automation tries to get a property from each in this order until one + * returns a value. If none do, the property isn't supported. + */ + if (Provider_override.ref == 2) + { + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb5, "reg_prov_cb5"); + } + + /* Property retrieved from Provider_proxy (Main) */ + Provider_override.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb6, "reg_prov_cb6"); + + /* Property retrieved from Provider_nc (Nonclient) */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb7, "reg_prov_cb7"); + + /* Property retrieved from Provider_hwnd (Hwnd) */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + Provider_nc.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_I4, "Unexpected vt %d\n", V_VT(&v)); + ok(V_I4(&v) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v)); + ok_method_sequence(reg_prov_cb8, "reg_prov_cb8"); + + /* Property retrieved from none of the providers. */ + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = TRUE; + Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = TRUE; + hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v)); + ok_method_sequence(reg_prov_cb9, "reg_prov_cb9"); + + UiaNodeRelease(node); + ok(Provider_proxy.ref == 1, "Unexpected refcnt %ld\n", Provider_proxy.ref); + ok(Provider_nc.ref == 1, "Unexpected refcnt %ld\n", Provider_nc.ref); + ok(Provider_hwnd.ref == 1, "Unexpected refcnt %ld\n", Provider_hwnd.ref); + ok(Provider_override.ref == 1, "Unexpected refcnt %ld\n", Provider_override.ref); + Provider_override.ret_invalid_prop_type = Provider_proxy.ret_invalid_prop_type = FALSE; + Provider_nc.ret_invalid_prop_type = Provider_hwnd.ret_invalid_prop_type = FALSE; + + /* + * Provider_hwnd has ProviderOptions_UseComThreading, and COM hasn't been + * initialized. One provider failing will cause the entire node to fail + * creation on Win10+. + */ + Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider | ProviderOptions_UseComThreading; + node = (void *)0xdeadbeef; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_proxy); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &node); + ok(hr == CO_E_NOTINITIALIZED || broken(hr == S_OK), "Unexpected hr %#lx.\n", hr); + ok(!node || broken(!!node), "node != NULL\n"); + todo_wine CHECK_CALLED(winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + CHECK_CALLED(prov_callback_proxy); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + ok_method_sequence(reg_prov_cb10, "reg_prov_cb10"); + UiaNodeRelease(node); + Provider_hwnd.prov_opts = ProviderOptions_ClientSideProvider; + + /* + * Provider returned by UiaRootObjectId on hwnd2. No ProviderType_Proxy + * callback for hwnd2. + */ + Provider.hwnd = hwnd2; + Provider.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &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(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb11, "reg_prov_cb11"); + + UiaNodeRelease(node); + + /* + * Provider returned by UiaRootObjectId on both HWNDs. Since Provider2 + * doesn't give an HWND override provider, UIA will attempt to get a proxy + * provider to check it for an HWND override provider. + */ + Provider.hwnd = hwnd2; + Provider2.hwnd = hwnd; + Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + prov_root = &Provider2.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &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(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + todo_wine CHECK_CALLED(prov_callback_parent_proxy); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb12, "reg_prov_cb12"); + + UiaNodeRelease(node); + + /* + * Provider returned by UiaRootObjectId on both HWNDs. Since Provider2 + * returns an HWND override, no ProviderType_Proxy callback for hwnd. + */ + Provider.hwnd = hwnd2; + Provider2.hwnd = hwnd; + Provider2.override_hwnd = Provider_override.hwnd = hwnd2; + Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = TRUE; + Provider.prov_opts = Provider2.prov_opts = ProviderOptions_ServerSideProvider; + child_win_prov_root = &Provider.IRawElementProviderSimple_iface; + prov_root = &Provider2.IRawElementProviderSimple_iface; + Provider_proxy2.override_hwnd = NULL; + SET_EXPECT(winproc_GETOBJECT_UiaRoot); + SET_EXPECT(child_winproc_GETOBJECT_UiaRoot); + SET_EXPECT(prov_callback_base_hwnd); + SET_EXPECT(prov_callback_nonclient); + SET_EXPECT(prov_callback_parent_proxy); + hr = UiaNodeFromHandle(hwnd2, &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(child_winproc_GETOBJECT_UiaRoot); + CHECK_CALLED(prov_callback_base_hwnd); + CHECK_CALLED(prov_callback_nonclient); + + hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); + todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + if (SUCCEEDED(hr)) + { + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2); + check_node_provider_desc(V_BSTR(&v), L"Override", L"Provider_override", TRUE); + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider_hwnd", FALSE); + check_node_provider_desc(V_BSTR(&v), L"Nonclient", L"Provider_nc", FALSE); + VariantClear(&v); + } + ok_method_sequence(reg_prov_cb13, "reg_prov_cb13"); + + UiaNodeRelease(node); + + Provider2.ignore_hwnd_prop = Provider_override.ignore_hwnd_prop = FALSE; + UiaRegisterProviderCallback(NULL); + + DestroyWindow(hwnd); + UnregisterClassA("UiaRegisterProviderCallback class", NULL); + UnregisterClassA("UiaRegisterProviderCallback child class", NULL); +} + /* * Once a process returns a UI Automation provider with * UiaReturnRawElementProvider it ends up in an implicit MTA until exit. This @@ -5876,6 +6718,8 @@ START_TEST(uiautomation) test_UiaNodeFromHandle(argv[0]); else if (!strcmp(argv[2], "UiaNodeFromHandle_client_proc")) test_UiaNodeFromHandle_client_proc(); + else if (!strcmp(argv[2], "UiaRegisterProviderCallback")) + test_UiaRegisterProviderCallback();
FreeLibrary(uia_dll); return; @@ -5889,6 +6733,7 @@ START_TEST(uiautomation) test_UiaGetRuntimeId(); test_UiaHUiaNodeFromVariant(); launch_test_process(argv[0], "UiaNodeFromHandle"); + launch_test_process(argv[0], "UiaRegisterProviderCallback"); if (uia_dll) { pUiaProviderFromIAccessible = (void *)GetProcAddress(uia_dll, "UiaProviderFromIAccessible"); diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 94046066354..05f7c027565 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -909,7 +909,7 @@ static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProvid return S_OK; }
-static HRESULT uia_get_provider_from_hwnd(struct uia_node *node); +static HRESULT uia_get_providers_for_hwnd(struct uia_node *node); HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers) { @@ -958,7 +958,11 @@ HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE }
if (node->hwnd && get_hwnd_providers) - uia_get_provider_from_hwnd(node); + { + hr = uia_get_providers_for_hwnd(node); + if (FAILED(hr)) + WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr); + }
hr = prepare_uia_node(node); if (FAILED(hr)) @@ -1406,9 +1410,9 @@ static HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode)
if (node->hwnd) { - hr = uia_get_provider_from_hwnd(node); + hr = uia_get_providers_for_hwnd(node); if (FAILED(hr)) - WARN("uia_get_provider_from_hwnd failed with hr %#lx\n", hr); + WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr); }
hr = prepare_uia_node(node); @@ -1445,9 +1449,8 @@ static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
if (!args.lr) { - FIXME("No native UIA provider for hwnd %p, MSAA proxy currently unimplemented.\n", node->hwnd); uia_stop_client_thread(); - return E_NOTIMPL; + return S_FALSE; }
args.unwrap = GetCurrentThreadId() == GetWindowThreadProcessId(node->hwnd, NULL); @@ -1482,7 +1485,7 @@ HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode) list_init(&node->node_map_list_entry); node->ref = 1;
- hr = uia_get_provider_from_hwnd(node); + hr = uia_get_providers_for_hwnd(node); if (FAILED(hr)) { heap_free(node); @@ -1776,3 +1779,135 @@ HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
return S_OK; } + +static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) +{ + switch (prov_type) + { + case ProviderType_Proxy: + FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n"); + break; + + case ProviderType_NonClientArea: + FIXME("Default ProviderType_NonClientArea provider unimplemented.\n"); + break; + + case ProviderType_BaseHwnd: + FIXME("Default ProviderType_BaseHwnd provider unimplemented.\n"); + break; + + default: + break; + } + + return NULL; +} + +static UiaProviderCallback *uia_provider_callback = default_uia_provider_callback; + +static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type, + int node_prov_type) +{ + IRawElementProviderSimple *elprov; + LONG lbound, elems; + SAFEARRAY *sa; + IUnknown *unk; + VARTYPE vt; + HRESULT hr; + + if (!(sa = uia_provider_callback(node->hwnd, prov_type))) + return S_OK; + + hr = SafeArrayGetVartype(sa, &vt); + if (FAILED(hr) || (vt != VT_UNKNOWN)) + goto exit; + + hr = get_safearray_bounds(sa, &lbound, &elems); + if (FAILED(hr)) + goto exit; + + /* Returned SAFEARRAY can only have 1 element. */ + if (elems != 1) + { + WARN("Invalid element count %ld for returned SAFEARRAY\n", elems); + goto exit; + } + + hr = SafeArrayGetElement(sa, &lbound, &unk); + if (FAILED(hr)) + goto exit; + + hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov); + IUnknown_Release(unk); + if (FAILED(hr) || !elprov) + { + WARN("Failed to get IRawElementProviderSimple from returned SAFEARRAY.\n"); + hr = S_OK; + goto exit; + } + + hr = create_wine_uia_provider(node, elprov, node_prov_type); + IRawElementProviderSimple_Release(elprov); + +exit: + if (FAILED(hr)) + WARN("Failed to get clientside provider, hr %#lx\n", hr); + SafeArrayDestroy(sa); + return hr; +} + +static HRESULT uia_get_providers_for_hwnd(struct uia_node *node) +{ + HRESULT hr; + + hr = uia_get_provider_from_hwnd(node); + if (FAILED(hr)) + return hr; + + if (!node->prov[PROV_TYPE_MAIN]) + { + hr = uia_get_clientside_provider(node, ProviderType_Proxy, PROV_TYPE_MAIN); + if (FAILED(hr)) + return hr; + } + + if (!node->prov[PROV_TYPE_OVERRIDE]) + FIXME("Override provider callback currently unimplemented.\n"); + + if (!node->prov[PROV_TYPE_NONCLIENT]) + { + hr = uia_get_clientside_provider(node, ProviderType_NonClientArea, PROV_TYPE_NONCLIENT); + if (FAILED(hr)) + return hr; + } + + if (!node->prov[PROV_TYPE_HWND]) + { + hr = uia_get_clientside_provider(node, ProviderType_BaseHwnd, PROV_TYPE_HWND); + if (FAILED(hr)) + return hr; + } + + if (!node->prov_count) + { + if (uia_provider_callback == default_uia_provider_callback) + return E_NOTIMPL; + else + return E_FAIL; + } + + return S_OK; +} + +/*********************************************************************** + * UiaRegisterProviderCallback (uiautomationcore.@) + */ +void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) +{ + TRACE("(%p)\n", callback); + + if (callback) + uia_provider_callback = callback; + else + uia_provider_callback = default_uia_provider_callback; +} diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c index c888b51a019..2c741398c82 100644 --- a/dlls/uiautomationcore/uia_main.c +++ b/dlls/uiautomationcore/uia_main.c @@ -317,11 +317,6 @@ HRESULT WINAPI UiaRaiseAutomationPropertyChangedEvent(IRawElementProviderSimple return S_OK; }
-void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback) -{ - FIXME("(%p): stub\n", callback); -} - HRESULT WINAPI UiaHostProviderFromHwnd(HWND hwnd, IRawElementProviderSimple **provider) { struct hwnd_host_provider *host_prov;
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=125137
Your paranoid android.
=== debian11 (build log) ===
Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24827. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24827. Use of uninitialized value $Flaky in addition (+) at /home/testbot/lib/WineTestBot/LogUtils.pm line 720, <$LogFile> line 24827.
Pipeline failures here are coming from d3drm tests failing, so it's not related...
This merge request was approved by Esme Povirk.