Commit a19c1ff1 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Add a default ProviderType_Proxy MSAA bridge clientside provider.

parent 2a089f52
......@@ -90,6 +90,7 @@ DEFINE_EXPECT(Accessible2_get_accName);
DEFINE_EXPECT(Accessible2_get_accRole);
DEFINE_EXPECT(Accessible2_get_accState);
DEFINE_EXPECT(Accessible2_accLocation);
DEFINE_EXPECT(Accessible_QI_IAccIdentity);
DEFINE_EXPECT(Accessible2_QI_IAccIdentity);
DEFINE_EXPECT(Accessible2_get_uniqueID);
DEFINE_EXPECT(Accessible_child_accNavigate);
......@@ -177,7 +178,10 @@ static HRESULT WINAPI Accessible_QueryInterface(IAccessible *iface, REFIID riid,
{
if (This == &Accessible2)
CHECK_EXPECT(Accessible2_QI_IAccIdentity);
ok(This == &Accessible2, "unexpected call\n");
else if (This == &Accessible)
CHECK_EXPECT(Accessible_QI_IAccIdentity);
ok(This == &Accessible2 || This == &Accessible, "unexpected call\n");
return E_NOINTERFACE;
}
......@@ -6738,10 +6742,17 @@ static void test_UiaNodeFromHandle(const char *name)
/* Only sent twice on Win7. */
SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2);
hr = UiaNodeFromHandle(hwnd, &node);
/* Windows 10 and below return E_FAIL, Windows 11 returns S_OK. */
ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr);
/*
* On all versions of Windows prior to Windows 11, this would fail due to
* COM being uninitialized, presumably because it tries to get an MSAA
* proxy. Windows 11 now has the thread end up in an implicit MTA after
* the call to UiaNodeFromHandle, which is probably why this now succeeds.
* I don't know of anything that relies on this behavior, so for now we
* won't match it.
*/
todo_wine 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);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
if (SUCCEEDED(hr))
UiaNodeRelease(node);
......@@ -6757,7 +6768,7 @@ static void test_UiaNodeFromHandle(const char *name)
hr = UiaNodeFromHandle(hwnd, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
......@@ -6783,7 +6794,7 @@ static void test_UiaNodeFromHandle(const char *name)
hr = UiaNodeFromHandle(hwnd, &node);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
......@@ -6818,7 +6829,7 @@ static void test_UiaNodeFromHandle(const char *name)
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);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
......@@ -12684,6 +12695,93 @@ static void test_default_clientside_providers(void)
UiaNodeRelease(node);
prov_root = NULL;
/*
* Test default ProviderType_Proxy clientside provider. Provider will be
* the HWND provider for this node, and Accessible will be the main
* provider.
*/
initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd, FALSE);
set_accessible_props(&Accessible, ROLE_SYSTEM_TEXT, STATE_SYSTEM_FOCUSABLE, 0, L"Accessible", 0, 0, 20, 20);
set_accessible_ia2_props(&Accessible, FALSE, 0);
acc_client = &Accessible.IAccessible_iface;
prov_root = child_win_prov_root = NULL;
SET_EXPECT(Accessible_QI_IAccIdentity);
SET_EXPECT(Accessible_get_accParent);
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
/* Only sent twice on Win7. */
SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2);
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);
ok(Accessible.ref >= 2, "Unexpected refcnt %ld\n", Accessible.ref);
todo_wine CHECK_CALLED(Accessible_QI_IAccIdentity);
todo_wine CHECK_CALLED(Accessible_get_accParent);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
CHECK_CALLED(winproc_GETOBJECT_CLIENT);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE);
check_node_provider_desc_todo(V_BSTR(&v), L"Nonclient", NULL, FALSE);
check_node_provider_desc(V_BSTR(&v), L"Main", NULL, TRUE);
VariantClear(&v);
SET_EXPECT(Accessible_get_accRole);
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_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v));
VariantClear(&v);
CHECK_CALLED(Accessible_get_accRole);
UiaNodeRelease(node);
ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
ok(Accessible.ref == 1, "Unexpected refcnt %ld\n", Accessible.ref);
/*
* Unlike UiaProviderFromIAccessible which won't create a provider for an
* MSAA proxy, the default clientside proxy provider will.
*/
hwnd2 = CreateWindowA("EDIT", "", WS_VISIBLE | WS_CHILD | ES_PASSWORD,
0, 0, 100, 100, hwnd, NULL, NULL, NULL);
initialize_provider(&Provider, ProviderOptions_ClientSideProvider, hwnd2, FALSE);
/* Tries to get override provider from parent HWND. */
SET_EXPECT(winproc_GETOBJECT_UiaRoot);
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);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd2);
check_node_provider_desc(V_BSTR(&v), L"Hwnd", L"Provider", FALSE);
check_node_provider_desc_todo(V_BSTR(&v), L"Main", NULL, FALSE);
check_node_provider_desc_todo(V_BSTR(&v), L"Annotation", NULL, TRUE);
VariantClear(&v);
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_EditControlTypeId, "Unexpected I4 %#lx\n", V_I4(&v));
VariantClear(&v);
hr = UiaGetPropertyValue(node, UIA_IsPasswordPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v) == VT_BOOL, "Unexpected VT %d\n", V_VT(&v));
ok(check_variant_bool(&v, TRUE), "V_BOOL(&v) = %#x\n", V_BOOL(&v));
VariantClear(&v);
UiaNodeRelease(node);
DestroyWindow(hwnd2);
set_accessible_props(&Accessible, 0, 0, 0, NULL, 0, 0, 0, 0);
acc_client = NULL;
prov_root = child_win_prov_root = NULL;
method_sequences_enabled = TRUE;
DestroyWindow(hwnd);
DestroyWindow(hwnd_child);
......
......@@ -2653,9 +2653,21 @@ static SAFEARRAY WINAPI *default_uia_provider_callback(HWND hwnd, enum ProviderT
switch (prov_type)
{
case ProviderType_Proxy:
FIXME("Default ProviderType_Proxy MSAA provider unimplemented.\n");
{
IAccessible *acc;
hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
if (FAILED(hr) || !acc)
break;
hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, &elprov);
if (FAILED(hr))
WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr);
IAccessible_Release(acc);
break;
}
case ProviderType_NonClientArea:
FIXME("Default ProviderType_NonClientArea provider unimplemented.\n");
break;
......
......@@ -155,3 +155,5 @@ HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov)
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;
HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc,
IRawElementProviderSimple **elprov) DECLSPEC_HIDDEN;
......@@ -796,7 +796,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
else
acc = msaa_prov->acc;
hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov);
hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, &elprov);
if (SUCCEEDED(hr))
{
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
......@@ -827,7 +827,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
if (FAILED(hr) || !acc)
break;
hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov);
if (SUCCEEDED(hr))
{
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
......@@ -877,7 +877,7 @@ static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
if (FAILED(hr) || !acc)
break;
hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
hr = create_msaa_provider(acc, child_id, NULL, FALSE, &elprov);
if (SUCCEEDED(hr))
{
struct msaa_provider *prov = impl_from_msaa_provider(elprov);
......@@ -1134,13 +1134,48 @@ static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = {
msaa_acc_provider_get_DefaultAction,
};
HRESULT create_msaa_provider(IAccessible *acc, long child_id, HWND hwnd, BOOL known_root_acc,
IRawElementProviderSimple **elprov)
{
struct msaa_provider *msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
if (!msaa_prov)
return E_OUTOFMEMORY;
msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
msaa_prov->refcount = 1;
variant_init_i4(&msaa_prov->cid, child_id);
msaa_prov->acc = acc;
IAccessible_AddRef(acc);
msaa_prov->ia2 = msaa_acc_get_ia2(acc);
if (!hwnd)
{
HRESULT hr;
hr = WindowFromAccessibleObject(acc, &msaa_prov->hwnd);
if (FAILED(hr))
WARN("WindowFromAccessibleObject failed with hr %#lx\n", hr);
}
else
msaa_prov->hwnd = hwnd;
if (known_root_acc)
msaa_prov->root_acc_check_ran = msaa_prov->is_root_acc = TRUE;
*elprov = &msaa_prov->IRawElementProviderSimple_iface;
return S_OK;
}
/***********************************************************************
* UiaProviderFromIAccessible (uiautomationcore.@)
*/
HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
IRawElementProviderSimple **elprov)
{
struct msaa_provider *msaa_prov;
IServiceProvider *serv_prov;
HWND hwnd = NULL;
HRESULT hr;
......@@ -1184,22 +1219,7 @@ HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD
if (!hwnd)
return E_FAIL;
msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
if (!msaa_prov)
return E_OUTOFMEMORY;
msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
msaa_prov->refcount = 1;
msaa_prov->hwnd = hwnd;
variant_init_i4(&msaa_prov->cid, child_id);
msaa_prov->acc = acc;
IAccessible_AddRef(acc);
msaa_prov->ia2 = msaa_acc_get_ia2(acc);
*elprov = &msaa_prov->IRawElementProviderSimple_iface;
return S_OK;
return create_msaa_provider(acc, child_id, hwnd, FALSE, elprov);
}
static HRESULT uia_get_hr_for_last_error(void)
......
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