uiautomationcore: Add support for UIAutomationType_Element properties.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
This commit is contained in:
Connor McAdams 2022-06-20 13:25:12 -04:00 committed by Alexandre Julliard
parent afb155145a
commit 0cea011921
3 changed files with 203 additions and 14 deletions

View file

@ -4153,15 +4153,11 @@ static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, V
VARIANT v1;
#ifdef _WIN64
todo_wine 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);
if (V_VT(v) != VT_I8)
break;
#else
todo_wine 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);
if (V_VT(v) != VT_I4)
break;
#endif
ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider_child.ref);
@ -4177,7 +4173,7 @@ static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, V
}
case UIAutomationType_ElementArray:
todo_wine ok(V_VT(v) == (VT_ARRAY | VT_UNKNOWN), "Unexpected VT %d\n", V_VT(v));
ok(V_VT(v) == (VT_ARRAY | VT_UNKNOWN), "Unexpected VT %d\n", V_VT(v));
if (V_VT(v) != (VT_ARRAY | VT_UNKNOWN))
break;

View file

@ -23,6 +23,131 @@
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
static void clear_uia_node_ptr_safearray(SAFEARRAY *sa, LONG elems)
{
HUIANODE node;
HRESULT hr;
LONG i;
for (i = 0; i < elems; i++)
{
hr = SafeArrayGetElement(sa, &i, &node);
if (FAILED(hr))
break;
UiaNodeRelease(node);
}
}
static void create_uia_node_safearray(VARIANT *in, VARIANT *out)
{
LONG i, idx, lbound, ubound, elems;
HUIANODE node;
SAFEARRAY *sa;
HRESULT hr;
UINT dims;
dims = SafeArrayGetDim(V_ARRAY(in));
if (!dims || (dims > 1))
{
WARN("Invalid dimensions %d for element safearray.\n", dims);
return;
}
hr = SafeArrayGetLBound(V_ARRAY(in), 1, &lbound);
if (FAILED(hr))
return;
hr = SafeArrayGetUBound(V_ARRAY(in), 1, &ubound);
if (FAILED(hr))
return;
elems = (ubound - lbound) + 1;
if (!(sa = SafeArrayCreateVector(VT_UINT_PTR, 0, elems)))
return;
for (i = 0; i < elems; i++)
{
IRawElementProviderSimple *elprov;
IUnknown *unk;
idx = lbound + i;
hr = SafeArrayGetElement(V_ARRAY(in), &idx, &unk);
if (FAILED(hr))
break;
hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov);
IUnknown_Release(unk);
if (FAILED(hr))
break;
hr = UiaNodeFromProvider(elprov, &node);
if (FAILED(hr))
break;
IRawElementProviderSimple_Release(elprov);
hr = SafeArrayPutElement(sa, &i, &node);
if (FAILED(hr))
break;
}
if (FAILED(hr))
{
clear_uia_node_ptr_safearray(sa, elems);
SafeArrayDestroy(sa);
return;
}
V_VT(out) = VT_UINT_PTR | VT_ARRAY;
V_ARRAY(out) = sa;
}
/* Convert a VT_UINT_PTR SAFEARRAY to VT_UNKNOWN. */
static void uia_node_ptr_to_unk_safearray(VARIANT *in)
{
SAFEARRAY *sa = NULL;
LONG ubound, i;
HUIANODE node;
HRESULT hr;
hr = SafeArrayGetUBound(V_ARRAY(in), 1, &ubound);
if (FAILED(hr))
goto exit;
if (!(sa = SafeArrayCreateVector(VT_UNKNOWN, 0, ubound + 1)))
{
hr = E_FAIL;
goto exit;
}
for (i = 0; i < (ubound + 1); i++)
{
hr = SafeArrayGetElement(V_ARRAY(in), &i, &node);
if (FAILED(hr))
break;
hr = SafeArrayPutElement(sa, &i, node);
if (FAILED(hr))
break;
UiaNodeRelease(node);
}
exit:
if (FAILED(hr))
{
clear_uia_node_ptr_safearray(V_ARRAY(in), ubound + 1);
if (sa)
SafeArrayDestroy(sa);
}
VariantClear(in);
if (SUCCEEDED(hr))
{
V_VT(in) = VT_UNKNOWN | VT_ARRAY;
V_ARRAY(in) = sa;
}
}
/*
* IWineUiaNode interface.
*/
@ -150,6 +275,17 @@ static ULONG WINAPI uia_provider_Release(IWineUiaProvider *iface)
return ref;
}
static void get_variant_for_node(HUIANODE node, VARIANT *v)
{
#ifdef _WIN64
V_VT(v) = VT_I8;
V_I8(v) = (UINT64)node;
#else
V_VT(v) = VT_I4;
V_I4(v) = (UINT32)node;
#endif
}
static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface,
const struct uia_prop_info *prop_info, VARIANT *ret_val)
{
@ -184,6 +320,43 @@ static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface,
*ret_val = v;
break;
case UIAutomationType_Element:
{
IRawElementProviderSimple *elprov;
HUIANODE node;
if (V_VT(&v) != VT_UNKNOWN)
{
WARN("Invalid vt %d for UIAutomationType_Element\n", V_VT(&v));
goto exit;
}
hr = IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IRawElementProviderSimple,
(void **)&elprov);
if (FAILED(hr))
goto exit;
hr = UiaNodeFromProvider(elprov, &node);
if (SUCCEEDED(hr))
{
get_variant_for_node(node, ret_val);
VariantClear(&v);
IRawElementProviderSimple_Release(elprov);
}
break;
}
case UIAutomationType_ElementArray:
if (V_VT(&v) != (VT_UNKNOWN | VT_ARRAY))
{
WARN("Invalid vt %d for UIAutomationType_ElementArray\n", V_VT(&v));
goto exit;
}
create_uia_node_safearray(&v, ret_val);
if (V_VT(ret_val) == (VT_UINT_PTR | VT_ARRAY))
VariantClear(&v);
break;
default:
break;
}
@ -315,7 +488,21 @@ HRESULT WINAPI UiaGetPropertyValue(HUIANODE huianode, PROPERTYID prop_id, VARIAN
VariantInit(&v);
hr = IWineUiaProvider_get_prop_val(prov, prop_info, &v);
if (SUCCEEDED(hr) && V_VT(&v) != VT_EMPTY)
*out_val = v;
{
/*
* ElementArray types come back as an array of pointers to prevent the
* HUIANODEs from getting marshaled. We need to convert them to
* VT_UNKNOWN here.
*/
if (prop_info->type == UIAutomationType_ElementArray)
{
uia_node_ptr_to_unk_safearray(&v);
if (V_VT(&v) != VT_EMPTY)
*out_val = v;
}
else
*out_val = v;
}
IWineUiaProvider_Release(prov);

View file

@ -51,7 +51,8 @@ static const struct uia_prop_info default_uia_properties[] = {
{ &Size_Property_GUID, UIA_SizePropertyId, },
{ &IsTextPattern2Available_Property_GUID, UIA_IsTextPattern2AvailablePropertyId, },
{ &Styles_FillPatternStyle_Property_GUID, UIA_StylesFillPatternStylePropertyId, },
{ &FlowsTo_Property_GUID, UIA_FlowsToPropertyId, },
{ &FlowsTo_Property_GUID, UIA_FlowsToPropertyId,
UIAutomationType_ElementArray, },
{ &ItemStatus_Property_GUID, UIA_ItemStatusPropertyId, },
{ &Scroll_VerticalViewSize_Property_GUID, UIA_ScrollVerticalViewSizePropertyId, },
{ &Selection_IsSelectionRequired_Property_GUID, UIA_SelectionIsSelectionRequiredPropertyId, },
@ -94,12 +95,14 @@ static const struct uia_prop_info default_uia_properties[] = {
{ &IsRangeValuePatternAvailable_Property_GUID, UIA_IsRangeValuePatternAvailablePropertyId, },
{ &IsScrollPatternAvailable_Property_GUID, UIA_IsScrollPatternAvailablePropertyId, },
{ &IsTransformPattern2Available_Property_GUID, UIA_IsTransformPattern2AvailablePropertyId, },
{ &LabeledBy_Property_GUID, UIA_LabeledByPropertyId, },
{ &LabeledBy_Property_GUID, UIA_LabeledByPropertyId,
UIAutomationType_Element, },
{ &ItemType_Property_GUID, UIA_ItemTypePropertyId, },
{ &Transform_CanMove_Property_GUID, UIA_TransformCanMovePropertyId, },
{ &LocalizedControlType_Property_GUID, UIA_LocalizedControlTypePropertyId, },
{ &Annotation_AnnotationTypeId_Property_GUID, UIA_AnnotationAnnotationTypeIdPropertyId, },
{ &FlowsFrom_Property_GUID, UIA_FlowsFromPropertyId, },
{ &FlowsFrom_Property_GUID, UIA_FlowsFromPropertyId,
UIAutomationType_ElementArray, },
{ &OptimizeForVisualContent_Property_GUID, UIA_OptimizeForVisualContentPropertyId, },
{ &IsVirtualizedItemPatternAvailable_Property_GUID, UIA_IsVirtualizedItemPatternAvailablePropertyId, },
{ &GridItem_Parent_Property_GUID, UIA_GridItemContainingGridPropertyId, },
@ -148,7 +151,8 @@ static const struct uia_prop_info default_uia_properties[] = {
{ &IsControlElement_Property_GUID, UIA_IsControlElementPropertyId, },
{ &HelpText_Property_GUID, UIA_HelpTextPropertyId, },
{ &Table_RowHeaders_Property_GUID, UIA_TableRowHeadersPropertyId, },
{ &ControllerFor_Property_GUID, UIA_ControllerForPropertyId, },
{ &ControllerFor_Property_GUID, UIA_ControllerForPropertyId,
UIAutomationType_ElementArray, },
{ &ProviderDescription_Property_GUID, UIA_ProviderDescriptionPropertyId, },
{ &AriaProperties_Property_GUID, UIA_AriaPropertiesPropertyId, },
{ &LiveSetting_Property_GUID, UIA_LiveSettingPropertyId,
@ -185,7 +189,8 @@ static const struct uia_prop_info default_uia_properties[] = {
{ &BoundingRectangle_Property_GUID, UIA_BoundingRectanglePropertyId, },
{ &LegacyIAccessible_Value_Property_GUID, UIA_LegacyIAccessibleValuePropertyId, },
{ &IsDragPatternAvailable_Property_GUID, UIA_IsDragPatternAvailablePropertyId, },
{ &DescribedBy_Property_GUID, UIA_DescribedByPropertyId, },
{ &DescribedBy_Property_GUID, UIA_DescribedByPropertyId,
UIAutomationType_ElementArray, },
{ &IsSelectionPatternAvailable_Property_GUID, UIA_IsSelectionPatternAvailablePropertyId, },
{ &Grid_RowCount_Property_GUID, UIA_GridRowCountPropertyId, },
{ &OutlineColor_Property_GUID, UIA_OutlineColorPropertyId,
@ -195,7 +200,8 @@ static const struct uia_prop_info default_uia_properties[] = {
{ &IsSynchronizedInputPatternAvailable_Property_GUID,UIA_IsSynchronizedInputPatternAvailablePropertyId, },
{ &OutlineThickness_Property_GUID, UIA_OutlineThicknessPropertyId, },
{ &IsLegacyIAccessiblePatternAvailable_Property_GUID,UIA_IsLegacyIAccessiblePatternAvailablePropertyId, },
{ &AnnotationObjects_Property_GUID, UIA_AnnotationObjectsPropertyId, },
{ &AnnotationObjects_Property_GUID, UIA_AnnotationObjectsPropertyId,
UIAutomationType_ElementArray, },
{ &IsRequiredForForm_Property_GUID, UIA_IsRequiredForFormPropertyId, },
{ &SpreadsheetItem_AnnotationTypes_Property_GUID, UIA_SpreadsheetItemAnnotationTypesPropertyId, },
{ &FillColor_Property_GUID, UIA_FillColorPropertyId,