Commit 8070e44f authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Add a default ProviderType_BaseHwnd clientside provider.

parent 3a456d51
......@@ -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();
......
......@@ -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;
......
......@@ -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;
......@@ -1203,6 +1203,147 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
}
/*
* 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.
*/
struct uia_provider_thread
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment