Commit 6254f663 authored by Connor McAdams's avatar Connor McAdams Committed by Alexandre Julliard

uiautomationcore: Implement IUIAutomationElement::GetCurrentPropertyValueEx.

parent 2d8bf67b
...@@ -4504,7 +4504,7 @@ static const struct prov_method_sequence node_from_prov8[] = { ...@@ -4504,7 +4504,7 @@ static const struct prov_method_sequence node_from_prov8[] = {
{ 0 } { 0 }
}; };
static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v); static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v, BOOL from_com);
static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param) static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param)
{ {
HUIANODE node = param; HUIANODE node = param;
...@@ -4523,7 +4523,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param) ...@@ -4523,7 +4523,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param)
hr = UiaGetPropertyValue(node, UIA_ProcessIdPropertyId, &v); hr = UiaGetPropertyValue(node, UIA_ProcessIdPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_ProcessIdPropertyId, UIAutomationType_Int, &v); check_uia_prop_val(UIA_ProcessIdPropertyId, UIAutomationType_Int, &v, FALSE);
/* /*
* When retrieving a UIAutomationType_Element property, if UseComThreading * When retrieving a UIAutomationType_Element property, if UseComThreading
...@@ -4537,7 +4537,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param) ...@@ -4537,7 +4537,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param)
Provider_child.expected_tid = Provider.expected_tid; Provider_child.expected_tid = Provider.expected_tid;
hr = UiaGetPropertyValue(node, UIA_LabeledByPropertyId, &v); hr = UiaGetPropertyValue(node, UIA_LabeledByPropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_LabeledByPropertyId, UIAutomationType_Element, &v); check_uia_prop_val(UIA_LabeledByPropertyId, UIAutomationType_Element, &v, FALSE);
/* Unset ProviderOptions_UseComThreading. */ /* Unset ProviderOptions_UseComThreading. */
Provider_child.prov_opts = ProviderOptions_ServerSideProvider; Provider_child.prov_opts = ProviderOptions_ServerSideProvider;
...@@ -4549,7 +4549,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param) ...@@ -4549,7 +4549,7 @@ static DWORD WINAPI uia_node_from_provider_test_com_thread(LPVOID param)
* called on the current thread. * called on the current thread.
*/ */
Provider_child.expected_tid = GetCurrentThreadId(); Provider_child.expected_tid = GetCurrentThreadId();
check_uia_prop_val(UIA_LabeledByPropertyId, UIAutomationType_Element, &v); check_uia_prop_val(UIA_LabeledByPropertyId, UIAutomationType_Element, &v, FALSE);
CoUninitialize(); CoUninitialize();
...@@ -4982,7 +4982,7 @@ static void check_uia_rect_val_(VARIANT *v, struct UiaRect *rect, const char *fi ...@@ -4982,7 +4982,7 @@ static void check_uia_rect_val_(VARIANT *v, struct UiaRect *rect, const char *fi
ok_(file, line)(tmp[3] == rect->height, "Unexpected height value %f, expected %f\n", tmp[3], rect->height); ok_(file, line)(tmp[3] == rect->height, "Unexpected height value %f, expected %f\n", tmp[3], rect->height);
} }
static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v) static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v, BOOL from_com)
{ {
LONG idx; LONG idx;
...@@ -5053,22 +5053,40 @@ static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, V ...@@ -5053,22 +5053,40 @@ static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, V
HRESULT hr; HRESULT hr;
VARIANT v1; VARIANT v1;
if (from_com)
{
IUIAutomationElement *elem;
ok(V_VT(v) == VT_UNKNOWN, "Unexpected VT %d\n", V_VT(v));
hr = IUnknown_QueryInterface(V_UNKNOWN(v), &IID_IUIAutomationElement, (void **)&elem);
VariantClear(v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref);
hr = IUIAutomationElement_GetCurrentPropertyValueEx(elem, UIA_ControlTypePropertyId, TRUE, &v1);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
IUIAutomationElement_Release(elem);
}
else
{
#ifdef _WIN64 #ifdef _WIN64
ok(V_VT(v) == VT_I8, "Unexpected VT %d\n", V_VT(v)); ok(V_VT(v) == VT_I8, "Unexpected VT %d\n", V_VT(v));
tmp_node = (HUIANODE)V_I8(v); tmp_node = (HUIANODE)V_I8(v);
#else #else
ok(V_VT(v) == VT_I4, "Unexpected VT %d\n", V_VT(v)); ok(V_VT(v) == VT_I4, "Unexpected VT %d\n", V_VT(v));
tmp_node = (HUIANODE)V_I4(v); tmp_node = (HUIANODE)V_I4(v);
#endif #endif
ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref); ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref);
hr = UiaGetPropertyValue(tmp_node, UIA_ControlTypePropertyId, &v1);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(UiaNodeRelease(tmp_node), "Failed to release node\n");
}
hr = UiaGetPropertyValue(tmp_node, UIA_ControlTypePropertyId, &v1);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
ok(V_VT(&v1) == VT_I4, "Unexpected VT %d\n", V_VT(&v1)); ok(V_VT(&v1) == VT_I4, "Unexpected VT %d\n", V_VT(&v1));
ok(V_I4(&v1) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v1)); ok(V_I4(&v1) == uia_i4_prop_val, "Unexpected I4 %#lx\n", V_I4(&v1));
ok(UiaNodeRelease(tmp_node), "Failed to release node\n");
ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref);
ok_method_sequence(get_elem_prop_seq, NULL); ok_method_sequence(get_elem_prop_seq, NULL);
break; break;
} }
...@@ -5214,7 +5232,7 @@ static void test_UiaGetPropertyValue(void) ...@@ -5214,7 +5232,7 @@ static void test_UiaGetPropertyValue(void)
winetest_push_context("prop_id %d", prop_id); winetest_push_context("prop_id %d", prop_id);
hr = UiaGetPropertyValue(node, prop_id, &v); hr = UiaGetPropertyValue(node, prop_id, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_uia_prop_val(prop_id, elem_prop->type, &v); check_uia_prop_val(prop_id, elem_prop->type, &v, FALSE);
/* /*
* Some properties have special behavior if an invalid value is * Some properties have special behavior if an invalid value is
...@@ -5973,7 +5991,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) ...@@ -5973,7 +5991,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v); check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v, FALSE);
/* /*
* On Windows, nested providers are always called on a separate thread if * On Windows, nested providers are always called on a separate thread if
...@@ -6132,7 +6150,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) ...@@ -6132,7 +6150,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v); check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v, FALSE);
/* Nodes returned from a nested node will be tracked and disconnectable. */ /* Nodes returned from a nested node will be tracked and disconnectable. */
Provider_child.prov_opts = ProviderOptions_ServerSideProvider; Provider_child.prov_opts = ProviderOptions_ServerSideProvider;
...@@ -6225,7 +6243,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) ...@@ -6225,7 +6243,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v); check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v, FALSE);
/* Finally, disconnect node. */ /* Finally, disconnect node. */
Provider.hwnd = hwnd; Provider.hwnd = hwnd;
...@@ -6447,7 +6465,7 @@ static void test_UiaNodeFromHandle(const char *name) ...@@ -6447,7 +6465,7 @@ static void test_UiaNodeFromHandle(const char *name)
Provider.expected_tid = GetCurrentThreadId(); Provider.expected_tid = GetCurrentThreadId();
hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v); hr = UiaGetPropertyValue(node, UIA_ControlTypePropertyId, &v);
ok(hr == S_OK, "Unexpected hr %#lx\n", hr); ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v); check_uia_prop_val(UIA_ControlTypePropertyId, UIAutomationType_Int, &v, FALSE);
/* UIAutomationType_Element properties will return a normal node. */ /* UIAutomationType_Element properties will return a normal node. */
Provider_child.prov_opts = ProviderOptions_ServerSideProvider; Provider_child.prov_opts = ProviderOptions_ServerSideProvider;
...@@ -9642,12 +9660,22 @@ static HWND create_test_hwnd(const char *class_name) ...@@ -9642,12 +9660,22 @@ static HWND create_test_hwnd(const char *class_name)
0, 0, 100, 100, NULL, NULL, NULL, NULL); 0, 0, 100, 100, NULL, NULL, NULL, NULL);
} }
static IUIAutomationElement *create_test_element_from_hwnd(IUIAutomation *uia_iface, HWND hwnd) static IUIAutomationElement *create_test_element_from_hwnd(IUIAutomation *uia_iface, HWND hwnd, BOOL block_hwnd_provs)
{ {
IUIAutomationElement *element; IUIAutomationElement *element;
HRESULT hr; HRESULT hr;
VARIANT v; VARIANT v;
if (block_hwnd_provs)
{
SET_EXPECT(prov_callback_base_hwnd);
SET_EXPECT(prov_callback_nonclient);
base_hwnd_prov = proxy_prov = parent_proxy_prov = nc_prov = NULL;
UiaRegisterProviderCallback(test_uia_provider_callback);
}
else
UiaRegisterProviderCallback(NULL);
initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd, TRUE); initialize_provider(&Provider, ProviderOptions_ServerSideProvider, hwnd, TRUE);
prov_root = &Provider.IRawElementProviderSimple_iface; prov_root = &Provider.IRawElementProviderSimple_iface;
SET_EXPECT(winproc_GETOBJECT_UiaRoot); SET_EXPECT(winproc_GETOBJECT_UiaRoot);
...@@ -9659,19 +9687,31 @@ static IUIAutomationElement *create_test_element_from_hwnd(IUIAutomation *uia_if ...@@ -9659,19 +9687,31 @@ static IUIAutomationElement *create_test_element_from_hwnd(IUIAutomation *uia_if
ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref);
CHECK_CALLED(winproc_GETOBJECT_UiaRoot); CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0; called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
if (block_hwnd_provs)
{
CHECK_CALLED(prov_callback_base_hwnd);
CHECK_CALLED(prov_callback_nonclient);
}
hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_ProviderDescriptionPropertyId, TRUE, &v); hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_ProviderDescriptionPropertyId, TRUE, &v);
todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr); todo_wine ok(hr == S_OK, "Unexpected hr %#lx\n", hr);
if (SUCCEEDED(hr)) if (SUCCEEDED(hr))
{ {
check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd); check_node_provider_desc_prefix(V_BSTR(&v), GetCurrentProcessId(), hwnd);
check_node_provider_desc(V_BSTR(&v), L"Main", L"Provider", FALSE); if (!block_hwnd_provs)
check_node_provider_desc(V_BSTR(&v), L"Nonclient", NULL, FALSE); {
check_node_provider_desc(V_BSTR(&v), L"Hwnd", NULL, TRUE); 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"Provider", TRUE);
VariantClear(&v); VariantClear(&v);
} }
ok_method_sequence(node_from_hwnd2, "create_test_element"); ok_method_sequence(node_from_hwnd2, "create_test_element");
UiaRegisterProviderCallback(NULL);
return element; return element;
} }
...@@ -9683,7 +9723,7 @@ static void test_ElementFromHandle(IUIAutomation *uia_iface, BOOL is_cui8) ...@@ -9683,7 +9723,7 @@ static void test_ElementFromHandle(IUIAutomation *uia_iface, BOOL is_cui8)
IUIAutomationElement *element; IUIAutomationElement *element;
HRESULT hr; HRESULT hr;
element = create_test_element_from_hwnd(uia_iface, hwnd); element = create_test_element_from_hwnd(uia_iface, hwnd, FALSE);
hr = IUIAutomationElement_QueryInterface(element, &IID_IUIAutomationElement2, (void **)&element_2); hr = IUIAutomationElement_QueryInterface(element, &IID_IUIAutomationElement2, (void **)&element_2);
if (is_cui8) if (is_cui8)
{ {
...@@ -9702,6 +9742,74 @@ static void test_ElementFromHandle(IUIAutomation *uia_iface, BOOL is_cui8) ...@@ -9702,6 +9742,74 @@ static void test_ElementFromHandle(IUIAutomation *uia_iface, BOOL is_cui8)
prov_root = NULL; prov_root = NULL;
} }
static void test_Element_GetPropertyValue(IUIAutomation *uia_iface)
{
HWND hwnd = create_test_hwnd("test_Element_GetPropertyValue class");
const struct uia_element_property *elem_prop;
IUIAutomationElement *element;
IUnknown *unk_ns;
int i, prop_id;
HRESULT hr;
VARIANT v;
element = create_test_element_from_hwnd(uia_iface, hwnd, TRUE);
Provider.frag_root = &Provider.IRawElementProviderFragmentRoot_iface;
initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, TRUE);
provider_add_child(&Provider, &Provider_child);
hr = UiaGetReservedNotSupportedValue(&unk_ns);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
VariantInit(&v);
for (i = 0; i < ARRAY_SIZE(element_properties); i++)
{
elem_prop = &element_properties[i];
/* Skip ElementArray properties for now. */
if (elem_prop->type == UIAutomationType_ElementArray)
continue;
Provider.ret_invalid_prop_type = FALSE;
VariantClear(&v);
if (!(prop_id = UiaLookupId(AutomationIdentifierType_Property, elem_prop->prop_guid)))
{
win_skip("No propertyId for GUID %s, skipping further tests.\n", debugstr_guid(elem_prop->prop_guid));
break;
}
winetest_push_context("Element prop_id %d", prop_id);
hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, prop_id, TRUE, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
check_uia_prop_val(prop_id, elem_prop->type, &v, TRUE);
/*
* Some properties have special behavior if an invalid value is
* returned, skip them here.
*/
if (!elem_prop->skip_invalid)
{
Provider.ret_invalid_prop_type = TRUE;
hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, prop_id, TRUE, &v);
ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
if (SUCCEEDED(hr))
{
ok_method_sequence(get_prop_invalid_type_seq, NULL);
ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v));
ok(V_UNKNOWN(&v) == unk_ns, "unexpected IUnknown %p\n", V_UNKNOWN(&v));
VariantClear(&v);
}
}
winetest_pop_context();
}
IUIAutomationElement_Release(element);
ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
DestroyWindow(hwnd);
UnregisterClassA("test_Element_GetPropertyValue class", NULL);
}
struct uia_com_classes { struct uia_com_classes {
const GUID *clsid; const GUID *clsid;
const GUID *iid; const GUID *iid;
...@@ -9766,6 +9874,7 @@ static void test_CUIAutomation(void) ...@@ -9766,6 +9874,7 @@ static void test_CUIAutomation(void)
ok(!!uia_iface, "uia_iface == NULL\n"); ok(!!uia_iface, "uia_iface == NULL\n");
test_ElementFromHandle(uia_iface, has_cui8); test_ElementFromHandle(uia_iface, has_cui8);
test_Element_GetPropertyValue(uia_iface);
IUIAutomation_Release(uia_iface); IUIAutomation_Release(uia_iface);
CoUninitialize(); CoUninitialize();
......
...@@ -134,11 +134,46 @@ static HRESULT WINAPI uia_element_GetCurrentPropertyValue(IUIAutomationElement9 ...@@ -134,11 +134,46 @@ static HRESULT WINAPI uia_element_GetCurrentPropertyValue(IUIAutomationElement9
return E_NOTIMPL; return E_NOTIMPL;
} }
static HRESULT create_uia_element(IUIAutomationElement **iface, BOOL from_cui8, HUIANODE node);
static HRESULT WINAPI uia_element_GetCurrentPropertyValueEx(IUIAutomationElement9 *iface, PROPERTYID prop_id, static HRESULT WINAPI uia_element_GetCurrentPropertyValueEx(IUIAutomationElement9 *iface, PROPERTYID prop_id,
BOOL ignore_default, VARIANT *ret_val) BOOL ignore_default, VARIANT *ret_val)
{ {
FIXME("%p: stub\n", iface); const struct uia_prop_info *prop_info = uia_prop_info_from_id(prop_id);
return E_NOTIMPL; struct uia_element *element = impl_from_IUIAutomationElement9(iface);
HRESULT hr;
TRACE("%p, %d, %d, %p\n", iface, prop_id, ignore_default, ret_val);
if (!ignore_default)
FIXME("Default values currently unimplemented\n");
VariantInit(ret_val);
if (prop_info->type == UIAutomationType_ElementArray)
{
FIXME("ElementArray property types currently unsupported for IUIAutomationElement\n");
return E_NOTIMPL;
}
hr = UiaGetPropertyValue(element->node, prop_id, ret_val);
if ((prop_info->type == UIAutomationType_Element) && (V_VT(ret_val) != VT_UNKNOWN))
{
IUIAutomationElement *out_elem;
HUIANODE node;
hr = UiaHUiaNodeFromVariant(ret_val, &node);
VariantClear(ret_val);
if (FAILED(hr))
return hr;
hr = create_uia_element(&out_elem, element->from_cui8, node);
if (SUCCEEDED(hr))
{
V_VT(ret_val) = VT_UNKNOWN;
V_UNKNOWN(ret_val) = (IUnknown *)out_elem;
}
}
return hr;
} }
static HRESULT WINAPI uia_element_GetCachedPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id, static HRESULT WINAPI uia_element_GetCachedPropertyValue(IUIAutomationElement9 *iface, PROPERTYID prop_id,
......
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