From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 10 +- dlls/uiautomationcore/uia_client.c | 189 ++++++++++++++++++++- dlls/uiautomationcore/uia_ids.c | 18 +- 3 files changed, 203 insertions(+), 14 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index dfd9f9b38df..ed3dfbb543c 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -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;
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index eae532d7b6c..1ce540a885a 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -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);
diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index 864925f0936..cab22f969c6 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -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,