From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 97 +++++++------- dlls/uiautomationcore/uia_client.c | 21 ++- dlls/uiautomationcore/uia_private.h | 1 + dlls/uiautomationcore/uia_provider.c | 141 +++++++++++++++++++++ 4 files changed, 205 insertions(+), 55 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index f3e671526ec..da9bb6aa5c9 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -6532,15 +6532,14 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
memset(buf, 0, sizeof(buf)); - todo_wine ok(get_nested_provider_desc(V_BSTR(&v), L"Main", TRUE, buf), "Failed to get nested provider description\n"); - if (lstrlenW(buf)) - { - check_node_provider_desc_prefix(buf, GetCurrentProcessId(), hwnd); - 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); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, FALSE); - } + 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); + 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_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, FALSE); VariantClear(&v);
Provider_child.ignore_hwnd_prop = FALSE; @@ -6749,7 +6748,7 @@ static void test_UiaNodeFromHandle(const char *name) SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); /* Windows 10 and below return E_FAIL, Windows 11 returns S_OK. */ - todo_wine ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); if (SUCCEEDED(hr)) @@ -6765,23 +6764,20 @@ static void test_UiaNodeFromHandle(const char *name) SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
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(), hwnd); - check_node_provider_desc(V_BSTR(&v), L"Annotation", NULL, FALSE); - 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", NULL, TRUE); - VariantClear(&v); - } + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc_todo(V_BSTR(&v), L"Annotation", NULL, FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Main", NULL, FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); + VariantClear(&v);
- todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n");
/* * COM initialized, but provider passed into UiaReturnRawElementProvider @@ -6794,24 +6790,22 @@ static void test_UiaNodeFromHandle(const char *name) SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
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(), hwnd); - check_node_provider_desc(V_BSTR(&v), L"Annotation", NULL, FALSE); - 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", NULL, TRUE); - VariantClear(&v); - } + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc_todo(V_BSTR(&v), L"Annotation", NULL, FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Main", NULL, FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); + VariantClear(&v); + ok_method_sequence(node_from_hwnd1, "node_from_hwnd1");
- todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n");
/* * COM initialized, but provider passed into UiaReturnRawElementProvider @@ -6830,31 +6824,29 @@ static void test_UiaNodeFromHandle(const char *name) Provider.runtime_id[0] = UiaAppendRuntimeId; Provider.runtime_id[1] = 1; hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(Provider.ref == 1 || broken(Provider.ref == 2), "Unexpected refcnt %ld\n", Provider.ref); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); - todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); - if (SUCCEEDED(hr)) + ok(hr == S_OK, "Unexpected hr %#lx\n", hr); + + check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + if (Provider.ref == 1 || get_provider_desc(V_BSTR(&v), L"Annotation:", NULL)) { - check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); + check_node_provider_desc_todo(V_BSTR(&v), L"Annotation", NULL, FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Main", NULL, FALSE); + } + else + check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE);
- if (get_provider_desc(V_BSTR(&v), L"Annotation:", NULL)) - { - check_node_provider_desc(V_BSTR(&v), L"Annotation", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Main", NULL, FALSE); - } - else - check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); + check_node_provider_desc_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE); + check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); + VariantClear(&v);
- check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); - check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); - VariantClear(&v); - } ok_method_sequence(node_from_hwnd9, "node_from_hwnd9"); - todo_wine ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); + ok(UiaNodeRelease(node), "UiaNodeRelease returned FALSE\n"); /* * Bug on Windows 8 through Win10v1709 - if we have a RuntimeId failure, * refcount doesn't get decremented. @@ -12335,9 +12327,8 @@ static void test_node_hwnd_provider_(HUIANODE node, HWND hwnd, const char *file, winetest_push_context("UIA_NativeWindowHandlePropertyId"); hr = UiaGetPropertyValue(node, UIA_NativeWindowHandlePropertyId, &v); ok_(file, line)(hr == S_OK, "Unexpected hr %#lx\n", hr); - todo_wine ok_(file, line)(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); - if (V_VT(&v) == VT_I4) - ok_(file, line)(V_I4(&v) == HandleToUlong(hwnd), "V_I4(&v) = %#lx, expected %#lx\n", V_I4(&v), HandleToUlong(hwnd)); + ok_(file, line)(V_VT(&v) == VT_I4, "Unexpected VT %d\n", V_VT(&v)); + ok_(file, line)(V_I4(&v) == HandleToUlong(hwnd), "V_I4(&v) = %#lx, expected %#lx\n", V_I4(&v), HandleToUlong(hwnd)); VariantClear(&v); winetest_pop_context();
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 92ff41e2c71..4c1f0e3e480 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -2646,6 +2646,10 @@ HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type) { + IRawElementProviderSimple *elprov = NULL; + SAFEARRAY *sa = NULL; + HRESULT hr; + switch (prov_type) { case ProviderType_Proxy: @@ -2657,14 +2661,27 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT break;
case ProviderType_BaseHwnd: - FIXME("Default ProviderType_BaseHwnd provider unimplemented.\n"); + hr = create_base_hwnd_provider(hwnd, &elprov); + if (FAILED(hr)) + WARN("create_base_hwnd_provider failed with hr %#lx\n", hr); break;
default: break; }
- return NULL; + if (elprov) + { + LONG idx = 0; + + sa = SafeArrayCreateVector(VT_UNKNOWN, 0, 1); + if (sa) + SafeArrayPutElement(sa, &idx, (void *)elprov); + + IRawElementProviderSimple_Release(elprov); + } + + return sa; }
static UiaProviderCallback *uia_provider_callback = default_uia_provider_callback; diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 63c6f7dde22..3b1f21645fb 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -151,6 +151,7 @@ const struct uia_pattern_info *uia_pattern_info_from_id(PATTERNID pattern_id) DE const struct uia_control_type_info *uia_control_type_info_from_id(CONTROLTYPEID control_type_id) DECLSPEC_HIDDEN;
/* uia_provider.c */ +HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN; void uia_stop_provider_thread(void) DECLSPEC_HIDDEN; void uia_provider_thread_remove_node(HUIANODE node) DECLSPEC_HIDDEN; LRESULT uia_lresult_from_node(HUIANODE huianode) DECLSPEC_HIDDEN; diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c index 59be5d3782a..4d081b2c921 100644 --- a/dlls/uiautomationcore/uia_provider.c +++ b/dlls/uiautomationcore/uia_provider.c @@ -1202,6 +1202,147 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD return S_OK; }
+/* + * Default ProviderType_BaseHwnd IRawElementProviderSimple interface. + */ +struct base_hwnd_provider { + IRawElementProviderSimple IRawElementProviderSimple_iface; + LONG refcount; + + HWND hwnd; +}; + +static inline struct base_hwnd_provider *impl_from_base_hwnd_provider(IRawElementProviderSimple *iface) +{ + return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderSimple_iface); +} + +static HRESULT WINAPI base_hwnd_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IRawElementProviderSimple_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI base_hwnd_provider_AddRef(IRawElementProviderSimple *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + ULONG refcount = InterlockedIncrement(&base_hwnd_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + return refcount; +} + +static ULONG WINAPI base_hwnd_provider_Release(IRawElementProviderSimple *iface) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + ULONG refcount = InterlockedDecrement(&base_hwnd_prov->refcount); + + TRACE("%p, refcount %ld\n", iface, refcount); + + if (!refcount) + heap_free(base_hwnd_prov); + + return refcount; +} + +static HRESULT WINAPI base_hwnd_provider_get_ProviderOptions(IRawElementProviderSimple *iface, + enum ProviderOptions *ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = ProviderOptions_ClientSideProvider; + return S_OK; +} + +static HRESULT WINAPI base_hwnd_provider_GetPatternProvider(IRawElementProviderSimple *iface, + PATTERNID pattern_id, IUnknown **ret_val) +{ + FIXME("%p, %d, %p: stub\n", iface, pattern_id, ret_val); + *ret_val = NULL; + return E_NOTIMPL; +} + +static HRESULT WINAPI base_hwnd_provider_GetPropertyValue(IRawElementProviderSimple *iface, + PROPERTYID prop_id, VARIANT *ret_val) +{ + struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface); + HRESULT hr = S_OK; + + TRACE("%p, %d, %p\n", iface, prop_id, ret_val); + + VariantInit(ret_val); + if (!IsWindow(base_hwnd_prov->hwnd)) + return UIA_E_ELEMENTNOTAVAILABLE; + + switch (prop_id) + { + case UIA_ProviderDescriptionPropertyId: + V_VT(ret_val) = VT_BSTR; + V_BSTR(ret_val) = SysAllocString(L"Wine: HWND Proxy"); + break; + + case UIA_NativeWindowHandlePropertyId: + V_VT(ret_val) = VT_I4; + V_I4(ret_val) = HandleToUlong(base_hwnd_prov->hwnd); + break; + + default: + break; + } + + if (FAILED(hr)) + VariantClear(ret_val); + + return hr; +} + +static HRESULT WINAPI base_hwnd_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface, + IRawElementProviderSimple **ret_val) +{ + TRACE("%p, %p\n", iface, ret_val); + *ret_val = NULL; + return S_OK; +} + +static const IRawElementProviderSimpleVtbl base_hwnd_provider_vtbl = { + base_hwnd_provider_QueryInterface, + base_hwnd_provider_AddRef, + base_hwnd_provider_Release, + base_hwnd_provider_get_ProviderOptions, + base_hwnd_provider_GetPatternProvider, + base_hwnd_provider_GetPropertyValue, + base_hwnd_provider_get_HostRawElementProvider, +}; + +HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov) +{ + struct base_hwnd_provider *base_hwnd_prov; + + *elprov = NULL; + + if (!hwnd) + return E_INVALIDARG; + + if (!IsWindow(hwnd)) + return UIA_E_ELEMENTNOTAVAILABLE; + + if (!(base_hwnd_prov = heap_alloc_zero(sizeof(*base_hwnd_prov)))) + return E_OUTOFMEMORY; + + base_hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &base_hwnd_provider_vtbl; + base_hwnd_prov->refcount = 1; + base_hwnd_prov->hwnd = hwnd; + *elprov = &base_hwnd_prov->IRawElementProviderSimple_iface; + + return S_OK; +} + /* * UI Automation provider thread functions. */