-- v2: uiautomationcore: Implement IUIAutomationElement::get_CurrentBoundingRectangle. uiautomationcore: Implement IUIAutomationElement::get_CurrentName. uiautomationcore: Implement IUIAutomationElement::get_CurrentControlType.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 46 ++++++++++++++ dlls/uiautomationcore/uia_classes.idl | 5 ++ dlls/uiautomationcore/uia_ids.c | 74 ++++++++++++++++++++++ include/uiautomationcoreapi.h | 45 +++++++++++++ 4 files changed, 170 insertions(+)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 5b58525e10d..a5f609511ed 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4342,6 +4342,51 @@ static const struct uia_lookup_id uia_pattern_lookup_ids[] = { { &CustomNavigation_Pattern_GUID, UIA_CustomNavigationPatternId }, };
+static const struct uia_lookup_id uia_control_type_lookup_ids[] = { + { &Button_Control_GUID, UIA_ButtonControlTypeId }, + { &Calendar_Control_GUID, UIA_CalendarControlTypeId }, + { &CheckBox_Control_GUID, UIA_CheckBoxControlTypeId }, + { &ComboBox_Control_GUID, UIA_ComboBoxControlTypeId }, + { &Edit_Control_GUID, UIA_EditControlTypeId }, + { &Hyperlink_Control_GUID, UIA_HyperlinkControlTypeId }, + { &Image_Control_GUID, UIA_ImageControlTypeId }, + { &ListItem_Control_GUID, UIA_ListItemControlTypeId }, + { &List_Control_GUID, UIA_ListControlTypeId }, + { &Menu_Control_GUID, UIA_MenuControlTypeId }, + { &MenuBar_Control_GUID, UIA_MenuBarControlTypeId }, + { &MenuItem_Control_GUID, UIA_MenuItemControlTypeId }, + { &ProgressBar_Control_GUID, UIA_ProgressBarControlTypeId }, + { &RadioButton_Control_GUID, UIA_RadioButtonControlTypeId }, + { &ScrollBar_Control_GUID, UIA_ScrollBarControlTypeId }, + { &Slider_Control_GUID, UIA_SliderControlTypeId }, + { &Spinner_Control_GUID, UIA_SpinnerControlTypeId }, + { &StatusBar_Control_GUID, UIA_StatusBarControlTypeId }, + { &Tab_Control_GUID, UIA_TabControlTypeId }, + { &TabItem_Control_GUID, UIA_TabItemControlTypeId }, + { &Text_Control_GUID, UIA_TextControlTypeId }, + { &ToolBar_Control_GUID, UIA_ToolBarControlTypeId }, + { &ToolTip_Control_GUID, UIA_ToolTipControlTypeId }, + { &Tree_Control_GUID, UIA_TreeControlTypeId }, + { &TreeItem_Control_GUID, UIA_TreeItemControlTypeId }, + { &Custom_Control_GUID, UIA_CustomControlTypeId }, + { &Group_Control_GUID, UIA_GroupControlTypeId }, + { &Thumb_Control_GUID, UIA_ThumbControlTypeId }, + { &DataGrid_Control_GUID, UIA_DataGridControlTypeId }, + { &DataItem_Control_GUID, UIA_DataItemControlTypeId }, + { &Document_Control_GUID, UIA_DocumentControlTypeId }, + { &SplitButton_Control_GUID, UIA_SplitButtonControlTypeId }, + { &Window_Control_GUID, UIA_WindowControlTypeId }, + { &Pane_Control_GUID, UIA_PaneControlTypeId }, + { &Header_Control_GUID, UIA_HeaderControlTypeId }, + { &HeaderItem_Control_GUID, UIA_HeaderItemControlTypeId }, + { &Table_Control_GUID, UIA_TableControlTypeId }, + { &TitleBar_Control_GUID, UIA_TitleBarControlTypeId }, + { &Separator_Control_GUID, UIA_SeparatorControlTypeId }, + /* Implemented on Win8+ */ + { &SemanticZoom_Control_GUID, UIA_SemanticZoomControlTypeId }, + { &AppBar_Control_GUID, UIA_AppBarControlTypeId }, +}; + static void test_UiaLookupId(void) { static const struct { @@ -4354,6 +4399,7 @@ static void test_UiaLookupId(void) { "property", AutomationIdentifierType_Property, uia_property_lookup_ids, ARRAY_SIZE(uia_property_lookup_ids) }, { "event", AutomationIdentifierType_Event, uia_event_lookup_ids, ARRAY_SIZE(uia_event_lookup_ids) }, { "pattern", AutomationIdentifierType_Pattern, uia_pattern_lookup_ids, ARRAY_SIZE(uia_pattern_lookup_ids) }, + { "control_type", AutomationIdentifierType_ControlType, uia_control_type_lookup_ids, ARRAY_SIZE(uia_control_type_lookup_ids) }, }; unsigned int i, y;
diff --git a/dlls/uiautomationcore/uia_classes.idl b/dlls/uiautomationcore/uia_classes.idl index aee34c0221d..7272a09bfd6 100644 --- a/dlls/uiautomationcore/uia_classes.idl +++ b/dlls/uiautomationcore/uia_classes.idl @@ -40,6 +40,11 @@ struct uia_pattern_info { const GUID *pattern_iid; };
+struct uia_control_type_info { + const GUID *guid; + int control_type_id; +}; + [ version(1.0), uuid(8a9ca8eb-856b-43d9-abd7-4a590054064f), diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index 7ad8da69cd4..bd49890cdc5 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -44,6 +44,13 @@ static int __cdecl uia_pattern_guid_compare(const void *a, const void *b) return memcmp(guid, pattern->guid, sizeof(*guid)); }
+static int __cdecl uia_control_type_guid_compare(const void *a, const void *b) +{ + const GUID *guid = a; + const struct uia_control_type_info *control = b; + return memcmp(guid, control->guid, sizeof(*guid)); +} + /* Sorted by GUID. */ static const struct uia_prop_info default_uia_properties[] = { { &AutomationId_Property_GUID, UIA_AutomationIdPropertyId, @@ -514,6 +521,62 @@ const struct uia_pattern_info *uia_pattern_info_from_id(PATTERNID pattern_id) return &default_uia_patterns[pattern_id_idx[pattern_id - PATTERN_ID_MIN]]; }
+/* Sorted by GUID. */ +static const struct uia_control_type_info default_uia_control_types[] = { + { &Table_Control_GUID, UIA_TableControlTypeId }, + { &StatusBar_Control_GUID, UIA_StatusBarControlTypeId }, + { &Group_Control_GUID, UIA_GroupControlTypeId }, + { &SplitButton_Control_GUID, UIA_SplitButtonControlTypeId }, + { &CheckBox_Control_GUID, UIA_CheckBoxControlTypeId }, + { &Hyperlink_Control_GUID, UIA_HyperlinkControlTypeId }, + { &Tab_Control_GUID, UIA_TabControlTypeId }, + { &ScrollBar_Control_GUID, UIA_ScrollBarControlTypeId }, + { &Spinner_Control_GUID, UIA_SpinnerControlTypeId }, + { &Menu_Control_GUID, UIA_MenuControlTypeId }, + { &Window_Control_GUID, UIA_WindowControlTypeId }, + { &DataItem_Control_GUID, UIA_DataItemControlTypeId }, + { &SemanticZoom_Control_GUID, UIA_SemanticZoomControlTypeId }, + { &Slider_Control_GUID, UIA_SliderControlTypeId }, + { &TabItem_Control_GUID, UIA_TabItemControlTypeId }, + { &MenuBar_Control_GUID, UIA_MenuBarControlTypeId }, + { &ToolBar_Control_GUID, UIA_ToolBarControlTypeId }, + { &Pane_Control_GUID, UIA_PaneControlTypeId }, + { &Button_Control_GUID, UIA_ButtonControlTypeId }, + { &ComboBox_Control_GUID, UIA_ComboBoxControlTypeId }, + { &Document_Control_GUID, UIA_DocumentControlTypeId }, + { &Thumb_Control_GUID, UIA_ThumbControlTypeId }, + { &ProgressBar_Control_GUID, UIA_ProgressBarControlTypeId }, + { &Calendar_Control_GUID, UIA_CalendarControlTypeId }, + { &AppBar_Control_GUID, UIA_AppBarControlTypeId }, + { &Tree_Control_GUID, UIA_TreeControlTypeId }, + { &Separator_Control_GUID, UIA_SeparatorControlTypeId }, + { &DataGrid_Control_GUID, UIA_DataGridControlTypeId }, + { &TreeItem_Control_GUID, UIA_TreeItemControlTypeId }, + { &TitleBar_Control_GUID, UIA_TitleBarControlTypeId }, + { &Custom_Control_GUID, UIA_CustomControlTypeId }, + { &Edit_Control_GUID, UIA_EditControlTypeId }, + { &HeaderItem_Control_GUID, UIA_HeaderItemControlTypeId }, + { &Header_Control_GUID, UIA_HeaderControlTypeId }, + { &ToolTip_Control_GUID, UIA_ToolTipControlTypeId }, + { &MenuItem_Control_GUID, UIA_MenuItemControlTypeId }, + { &RadioButton_Control_GUID, UIA_RadioButtonControlTypeId }, + { &Text_Control_GUID, UIA_TextControlTypeId }, + { &List_Control_GUID, UIA_ListControlTypeId }, + { &Image_Control_GUID, UIA_ImageControlTypeId }, + { &ListItem_Control_GUID, UIA_ListItemControlTypeId }, +}; + +static const struct uia_control_type_info *uia_control_type_info_from_guid(const GUID *guid) +{ + struct uia_control_type_info *control_type; + + if ((control_type = bsearch(guid, default_uia_control_types, ARRAY_SIZE(default_uia_control_types), + sizeof(*control_type), uia_control_type_guid_compare))) + return control_type; + + return NULL; +} + /*********************************************************************** * UiaLookupId (uiautomationcore.@) */ @@ -562,6 +625,17 @@ int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid) }
case AutomationIdentifierType_ControlType: + { + const struct uia_control_type_info *control_type = uia_control_type_info_from_guid(guid); + + if (control_type) + ret_id = control_type->control_type_id; + else + FIXME("Failed to find control type Id for GUID %s\n", debugstr_guid(guid)); + + break; + } + case AutomationIdentifierType_TextAttribute: case AutomationIdentifierType_LandmarkType: case AutomationIdentifierType_Annotation: diff --git a/include/uiautomationcoreapi.h b/include/uiautomationcoreapi.h index 6f0bfaf4ecd..1d78113e1fd 100644 --- a/include/uiautomationcoreapi.h +++ b/include/uiautomationcoreapi.h @@ -299,6 +299,51 @@ DEFINE_GUID(DropTarget_Pattern_GUID, 0x0bcbec56,0xbd34,0x4b7b,0x9f,0xd5,0 DEFINE_GUID(TextEdit_Pattern_GUID, 0x69f3ff89,0x5af9,0x4c75,0x93,0x40,0xf2,0xde,0x29,0x2e,0x45,0x91); DEFINE_GUID(CustomNavigation_Pattern_GUID, 0xafea938a,0x621e,0x4054,0xbb,0x2c,0x2f,0x46,0x11,0x4d,0xac,0x3f);
+/* + * AutomationIdentifierType_ControlType GUIDs. + */ +DEFINE_GUID(Button_Control_GUID, 0x5a78e369,0xc6a1,0x4f33,0xa9,0xd7,0x79,0xf2,0x0d,0x0c,0x78,0x8e); +DEFINE_GUID(Calendar_Control_GUID, 0x8913eb88,0x00e5,0x46bc,0x8e,0x4e,0x14,0xa7,0x86,0xe1,0x65,0xa1); +DEFINE_GUID(CheckBox_Control_GUID, 0xfb50f922,0xa3db,0x49c0,0x8b,0xc3,0x06,0xda,0xd5,0x57,0x78,0xe2); +DEFINE_GUID(ComboBox_Control_GUID, 0x54cb426c,0x2f33,0x4fff,0xaa,0xa1,0xae,0xf6,0x0d,0xac,0x5d,0xeb); +DEFINE_GUID(Edit_Control_GUID, 0x6504a5c8,0x2c86,0x4f87,0xae,0x7b,0x1a,0xbd,0xdc,0x81,0x0c,0xf9); +DEFINE_GUID(Hyperlink_Control_GUID, 0x8a56022c,0xb00d,0x4d15,0x8f,0xf0,0x5b,0x6b,0x26,0x6e,0x5e,0x02); +DEFINE_GUID(Image_Control_GUID, 0x2d3736e4,0x6b16,0x4c57,0xa9,0x62,0xf9,0x32,0x60,0xa7,0x52,0x43); +DEFINE_GUID(ListItem_Control_GUID, 0x7b3717f2,0x44d1,0x4a58,0x98,0xa8,0xf1,0x2a,0x9b,0x8f,0x78,0xe2); +DEFINE_GUID(List_Control_GUID, 0x9b149ee1,0x7cca,0x4cfc,0x9a,0xf1,0xca,0xc7,0xbd,0xdd,0x30,0x31); +DEFINE_GUID(Menu_Control_GUID, 0x2e9b1440,0x0ea8,0x41fd,0xb3,0x74,0xc1,0xea,0x6f,0x50,0x3c,0xd1); +DEFINE_GUID(MenuBar_Control_GUID, 0xcc384250,0x0e7b,0x4ae8,0x95,0xae,0xa0,0x8f,0x26,0x1b,0x52,0xee); +DEFINE_GUID(MenuItem_Control_GUID, 0xf45225d3,0xd0a0,0x49d8,0x98,0x34,0x9a,0x00,0x0d,0x2a,0xed,0xdc); +DEFINE_GUID(ProgressBar_Control_GUID, 0x228c9f86,0xc36c,0x47bb,0x9f,0xb6,0xa5,0x83,0x4b,0xfc,0x53,0xa4); +DEFINE_GUID(RadioButton_Control_GUID, 0x3bdb49db,0xfe2c,0x4483,0xb3,0xe1,0xe5,0x7f,0x21,0x94,0x40,0xc6); +DEFINE_GUID(ScrollBar_Control_GUID, 0xdaf34b36,0x5065,0x4946,0xb2,0x2f,0x92,0x59,0x5f,0xc0,0x75,0x1a); +DEFINE_GUID(Slider_Control_GUID, 0xb033c24b,0x3b35,0x4cea,0xb6,0x09,0x76,0x36,0x82,0xfa,0x66,0x0b); +DEFINE_GUID(Spinner_Control_GUID, 0x60cc4b38,0x3cb1,0x4161,0xb4,0x42,0xc6,0xb7,0x26,0xc1,0x78,0x25); +DEFINE_GUID(StatusBar_Control_GUID, 0xd45e7d1b,0x5873,0x475f,0x95,0xa4,0x04,0x33,0xe1,0xf1,0xb0,0x0a); +DEFINE_GUID(Tab_Control_GUID, 0x38cd1f2d,0x337a,0x4bd2,0xa5,0xe3,0xad,0xb4,0x69,0xe3,0x0b,0xd3); +DEFINE_GUID(TabItem_Control_GUID, 0x2c6a634f,0x921b,0x4e6e,0xb2,0x6e,0x08,0xfc,0xb0,0x79,0x8f,0x4c); +DEFINE_GUID(Text_Control_GUID, 0xae9772dc,0xd331,0x4f09,0xbe,0x20,0x7e,0x6d,0xfa,0xf0,0x7b,0x0a); +DEFINE_GUID(ToolBar_Control_GUID, 0x8f06b751,0xe182,0x4e98,0x88,0x93,0x22,0x84,0x54,0x3a,0x7d,0xce); +DEFINE_GUID(ToolTip_Control_GUID, 0x05ddc6d1,0x2137,0x4768,0x98,0xea,0x73,0xf5,0x2f,0x71,0x34,0xf3); +DEFINE_GUID(Tree_Control_GUID, 0x7561349c,0xd241,0x43f4,0x99,0x08,0xb5,0xf0,0x91,0xbe,0xe6,0x11); +DEFINE_GUID(TreeItem_Control_GUID, 0x62c9feb9,0x8ffc,0x4878,0xa3,0xa4,0x96,0xb0,0x30,0x31,0x5c,0x18); +DEFINE_GUID(Custom_Control_GUID, 0xf29ea0c3,0xadb7,0x430a,0xba,0x90,0xe5,0x2c,0x73,0x13,0xe6,0xed); +DEFINE_GUID(Group_Control_GUID, 0xad50aa1c,0xe8c8,0x4774,0xae,0x1b,0xdd,0x86,0xdf,0x0b,0x3b,0xdc); +DEFINE_GUID(Thumb_Control_GUID, 0x701ca877,0xe310,0x4dd6,0xb6,0x44,0x79,0x7e,0x4f,0xae,0xa2,0x13); +DEFINE_GUID(DataGrid_Control_GUID, 0x84b783af,0xd103,0x4b0a,0x84,0x15,0xe7,0x39,0x42,0x41,0x0f,0x4b); +DEFINE_GUID(DataItem_Control_GUID, 0xa0177842,0xd94f,0x42a5,0x81,0x4b,0x60,0x68,0xad,0xdc,0x8d,0xa5); +DEFINE_GUID(Document_Control_GUID, 0x3cd6bb6f,0x6f08,0x4562,0xb2,0x29,0xe4,0xe2,0xfc,0x7a,0x9e,0xb4); +DEFINE_GUID(SplitButton_Control_GUID, 0x7011f01f,0x4ace,0x4901,0xb4,0x61,0x92,0x0a,0x6f,0x1c,0xa6,0x50); +DEFINE_GUID(Window_Control_GUID, 0xe13a7242,0xf462,0x4f4d,0xae,0xc1,0x53,0xb2,0x8d,0x6c,0x32,0x90); +DEFINE_GUID(Pane_Control_GUID, 0x5c2b3f5b,0x9182,0x42a3,0x8d,0xec,0x8c,0x04,0xc1,0xee,0x63,0x4d); +DEFINE_GUID(Header_Control_GUID, 0x5b90cbce,0x78fb,0x4614,0x82,0xb6,0x55,0x4d,0x74,0x71,0x8e,0x67); +DEFINE_GUID(HeaderItem_Control_GUID, 0xe6bc12cb,0x7c8e,0x49cf,0xb1,0x68,0x4a,0x93,0xa3,0x2b,0xeb,0xb0); +DEFINE_GUID(Table_Control_GUID, 0x773bfa0e,0x5bc4,0x4deb,0x92,0x1b,0xde,0x7b,0x32,0x06,0x22,0x9e); +DEFINE_GUID(TitleBar_Control_GUID, 0x98aa55bf,0x3bb0,0x4b65,0x83,0x6e,0x2e,0xa3,0x0d,0xbc,0x17,0x1f); +DEFINE_GUID(Separator_Control_GUID, 0x8767eba3,0x2a63,0x4ab0,0xac,0x8d,0xaa,0x50,0xe2,0x3d,0xe9,0x78); +DEFINE_GUID(SemanticZoom_Control_GUID, 0x5fd34a43,0x061e,0x42c8,0xb5,0x89,0x9d,0xcc,0xf7,0x4b,0xc4,0x3a); +DEFINE_GUID(AppBar_Control_GUID, 0x6114908d,0xcc02,0x4d37,0x87,0x5b,0xb5,0x30,0xc7,0x13,0x95,0x54); + enum AutomationIdentifierType { AutomationIdentifierType_Property,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 38 +++++++++++++++++++++- dlls/uiautomationcore/uia_com_client.c | 22 +++++++++++-- dlls/uiautomationcore/uia_ids.c | 20 ++++++++++++ dlls/uiautomationcore/uia_private.h | 1 + 4 files changed, 78 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a5f609511ed..a5b15726c21 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -9792,9 +9792,10 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) { HWND hwnd = create_test_hwnd("test_Element_GetPropertyValue class"); const struct uia_element_property *elem_prop; + struct Provider_prop_override prop_override; IUIAutomationElement *element; + int i, prop_id, tmp_int; IUnknown *unk_ns; - int i, prop_id; HRESULT hr; VARIANT v;
@@ -9849,6 +9850,41 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) winetest_pop_context(); }
+ /* + * IUIAutomationElement_get_CurrentControlType tests. If the value + * returned for UIA_ControlTypePropertyId is not a registered control + * type ID, we'll get back UIA_CustomControlTypeId. + */ + tmp_int = 0xdeadb33f; + hr = IUIAutomationElement_get_CurrentControlType(element, &tmp_int); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + /* + * Win10v1507 and below don't check whether or not the returned control + * type ID is valid. + */ + ok(tmp_int == UIA_CustomControlTypeId || broken(tmp_int == 0xdeadbeef), "Unexpected control type %#x\n", tmp_int); + ok_method_sequence(get_prop_seq, NULL); + + Provider.ret_invalid_prop_type = TRUE; + tmp_int = 0xdeadbeef; + hr = IUIAutomationElement_get_CurrentControlType(element, &tmp_int); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_int == UIA_CustomControlTypeId, "Unexpected control type %#x\n", tmp_int); + Provider.ret_invalid_prop_type = FALSE; + ok_method_sequence(get_prop_invalid_type_seq, NULL); + + /* Finally, a valid control type. */ + V_VT(&v) = VT_I4; + V_I4(&v) = UIA_HyperlinkControlTypeId; + set_property_override(&prop_override, UIA_ControlTypePropertyId, &v); + set_provider_prop_override(&Provider, &prop_override, 1); + hr = IUIAutomationElement_get_CurrentControlType(element, &tmp_int); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_int == UIA_HyperlinkControlTypeId, "Unexpected control type %#x\n", tmp_int); + set_provider_prop_override(&Provider, NULL, 0); + ok_method_sequence(get_prop_seq, NULL); + IUIAutomationElement_Release(element); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 6eea03a4d32..dad5938a760 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -239,8 +239,26 @@ static HRESULT WINAPI uia_element_get_CurrentProcessId(IUIAutomationElement9 *if
static HRESULT WINAPI uia_element_get_CurrentControlType(IUIAutomationElement9 *iface, CONTROLTYPEID *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + const struct uia_control_type_info *control_type_info = NULL; + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", iface, ret_val); + + VariantInit(&v); + *ret_val = UIA_CustomControlTypeId; + hr = UiaGetPropertyValue(element->node, UIA_ControlTypePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_I4) + { + if ((control_type_info = uia_control_type_info_from_id(V_I4(&v)))) + *ret_val = control_type_info->control_type_id; + else + WARN("Provider returned invalid control type ID %ld\n", V_I4(&v)); + } + + VariantClear(&v); + return hr; }
static HRESULT WINAPI uia_element_get_CurrentLocalizedControlType(IUIAutomationElement9 *iface, BSTR *ret_val) diff --git a/dlls/uiautomationcore/uia_ids.c b/dlls/uiautomationcore/uia_ids.c index bd49890cdc5..64f2ecced93 100644 --- a/dlls/uiautomationcore/uia_ids.c +++ b/dlls/uiautomationcore/uia_ids.c @@ -566,6 +566,18 @@ static const struct uia_control_type_info default_uia_control_types[] = { { &ListItem_Control_GUID, UIA_ListItemControlTypeId }, };
+static const int control_type_id_idx[] = { + 0x12, 0x17, 0x04, 0x13, 0x1f, 0x05, 0x27, 0x28, + 0x26, 0x09, 0x0f, 0x23, 0x16, 0x24, 0x07, 0x0d, + 0x08, 0x01, 0x06, 0x0e, 0x25, 0x10, 0x22, 0x19, + 0x1c, 0x1e, 0x02, 0x15, 0x1b, 0x0b, 0x14, 0x03, + 0x0a, 0x11, 0x21, 0x20, 0x00, 0x1d, 0x1a, 0x0c, + 0x18, +}; + +#define CONTROL_TYPE_ID_MIN 50000 +#define CONTROL_TYPE_ID_MAX (CONTROL_TYPE_ID_MIN + ARRAY_SIZE(default_uia_control_types)) + static const struct uia_control_type_info *uia_control_type_info_from_guid(const GUID *guid) { struct uia_control_type_info *control_type; @@ -577,6 +589,14 @@ static const struct uia_control_type_info *uia_control_type_info_from_guid(const return NULL; }
+const struct uia_control_type_info *uia_control_type_info_from_id(CONTROLTYPEID control_type_id) +{ + if ((control_type_id < CONTROL_TYPE_ID_MIN) || (control_type_id > CONTROL_TYPE_ID_MAX)) + return NULL; + + return &default_uia_control_types[control_type_id_idx[control_type_id - CONTROL_TYPE_ID_MIN]]; +} + /*********************************************************************** * UiaLookupId (uiautomationcore.@) */ diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 814ad43d686..157ae3583f8 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -110,6 +110,7 @@ HRESULT create_uia_iface(IUnknown **iface, BOOL is_cui8) DECLSPEC_HIDDEN; /* uia_ids.c */ const struct uia_prop_info *uia_prop_info_from_id(PROPERTYID prop_id) DECLSPEC_HIDDEN; const struct uia_pattern_info *uia_pattern_info_from_id(PATTERNID pattern_id) DECLSPEC_HIDDEN; +const struct uia_control_type_info *uia_control_type_info_from_id(CONTROLTYPEID control_type_id) DECLSPEC_HIDDEN;
/* uia_provider.c */ void uia_stop_provider_thread(void) DECLSPEC_HIDDEN;
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 20 ++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 17 +++++++++++++++-- 2 files changed, 35 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a5b15726c21..1fd25a49441 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -9796,6 +9796,7 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) IUIAutomationElement *element; int i, prop_id, tmp_int; IUnknown *unk_ns; + BSTR tmp_bstr; HRESULT hr; VARIANT v;
@@ -9885,6 +9886,25 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) set_provider_prop_override(&Provider, NULL, 0); ok_method_sequence(get_prop_seq, NULL);
+ /* + * IUIAutomationElement_get_CurrentName tests. + */ + tmp_bstr = NULL; + hr = IUIAutomationElement_get_CurrentName(element, &tmp_bstr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(tmp_bstr, uia_bstr_prop_str), "Unexpected BSTR %s\n", wine_dbgstr_w(tmp_bstr)); + SysFreeString(tmp_bstr); + ok_method_sequence(get_prop_seq, NULL); + + tmp_bstr = NULL; + Provider.ret_invalid_prop_type = TRUE; + hr = IUIAutomationElement_get_CurrentName(element, &tmp_bstr); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!lstrcmpW(tmp_bstr, L""), "Unexpected BSTR %s\n", wine_dbgstr_w(tmp_bstr)); + SysFreeString(tmp_bstr); + Provider.ret_invalid_prop_type = FALSE; + ok_method_sequence(get_prop_invalid_type_seq, NULL); + IUIAutomationElement_Release(element); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index dad5938a760..8cc39a9342f 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -269,8 +269,21 @@ static HRESULT WINAPI uia_element_get_CurrentLocalizedControlType(IUIAutomationE
static HRESULT WINAPI uia_element_get_CurrentName(IUIAutomationElement9 *iface, BSTR *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", iface, ret_val); + + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, UIA_NamePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == VT_BSTR && V_BSTR(&v)) + *ret_val = SysAllocString(V_BSTR(&v)); + else + *ret_val = SysAllocString(L""); + + VariantClear(&v); + return hr; }
static HRESULT WINAPI uia_element_get_CurrentAcceleratorKey(IUIAutomationElement9 *iface, BSTR *ret_val)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 105 ++++++++++++++++++++- dlls/uiautomationcore/uia_com_client.c | 27 +++++- 2 files changed, 128 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1fd25a49441..73b0db3073c 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -4968,6 +4968,34 @@ static const struct prov_method_sequence get_bounding_rect_seq[] = { { 0 } };
+static const struct prov_method_sequence get_bounding_rect_seq2[] = { + { &Provider, PROV_GET_PROPERTY_VALUE }, + NODE_CREATE_SEQ(&Provider_child), + { &Provider_child, FRAG_GET_BOUNDING_RECT }, + /* + * Win10v21H2+ and above call these, attempting to get the fragment root's + * HWND. I'm guessing this is an attempt to get the HWND's DPI for DPI scaling. + */ + { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { 0 } +}; + +static const struct prov_method_sequence get_bounding_rect_seq3[] = { + { &Provider_child, FRAG_GET_BOUNDING_RECT }, + /* + * Win10v21H2+ and above call these, attempting to get the fragment root's + * HWND. I'm guessing this is an attempt to get the HWND's DPI for DPI scaling. + */ + { &Provider_child, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ + { &Provider, FRAG_GET_FRAGMENT_ROOT, METHOD_OPTIONAL }, + { 0 } +}; + static const struct prov_method_sequence get_empty_bounding_rect_seq[] = { { &Provider_child, FRAG_GET_BOUNDING_RECT }, { 0 } @@ -5028,6 +5056,18 @@ 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); }
+#define check_uia_rect_rect_val( rect, uia_rect ) \ + check_uia_rect_rect_val_( (rect), (uia_rect), __FILE__, __LINE__) +static void check_uia_rect_rect_val_(RECT *rect, struct UiaRect *uia_rect, const char *file, int line) +{ + ok_(file, line)(rect->left == (LONG)uia_rect->left, "Unexpected left value %ld, expected %ld\n", rect->left, (LONG)uia_rect->left); + ok_(file, line)(rect->top == (LONG)uia_rect->top, "Unexpected top value %ld, expected %ld\n", rect->top, (LONG)uia_rect->top); + ok_(file, line)(rect->right == (LONG)(uia_rect->left + uia_rect->width), "Unexpected right value %ld, expected %ld\n", rect->right, + (LONG)(uia_rect->left + uia_rect->width)); + ok_(file, line)(rect->bottom == (LONG)(uia_rect->top + uia_rect->height), "Unexpected bottom value %ld, expected %ld\n", rect->bottom, + (LONG)(uia_rect->top + uia_rect->height)); +} + static void check_uia_prop_val(PROPERTYID prop_id, enum UIAutomationType type, VARIANT *v, BOOL from_com) { LONG idx; @@ -9793,11 +9833,13 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) HWND hwnd = create_test_hwnd("test_Element_GetPropertyValue class"); const struct uia_element_property *elem_prop; struct Provider_prop_override prop_override; - IUIAutomationElement *element; + IUIAutomationElement *element, *element2; int i, prop_id, tmp_int; + struct UiaRect uia_rect; IUnknown *unk_ns; BSTR tmp_bstr; HRESULT hr; + RECT rect; VARIANT v;
element = create_test_element_from_hwnd(uia_iface, hwnd, TRUE); @@ -9902,9 +9944,68 @@ static void test_Element_GetPropertyValue(IUIAutomation *uia_iface) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(!lstrcmpW(tmp_bstr, L""), "Unexpected BSTR %s\n", wine_dbgstr_w(tmp_bstr)); SysFreeString(tmp_bstr); - Provider.ret_invalid_prop_type = FALSE; + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, FALSE); ok_method_sequence(get_prop_invalid_type_seq, NULL);
+ /* + * Windows 7 will call get_FragmentRoot in an endless loop until the fragment root returns an HWND. + * It's the only version with this behavior. + */ + if (!UiaLookupId(AutomationIdentifierType_Property, &OptimizeForVisualContent_Property_GUID)) + { + win_skip("Skipping UIA_BoundingRectanglePropertyId tests for Win7\n"); + goto exit; + } + + /* + * IUIAutomationElement_get_CurrentBoundingRectangle/UIA_BoundRectanglePropertyId tests. + */ + hr = IUIAutomationElement_GetCurrentPropertyValueEx(element, UIA_LabeledByPropertyId, TRUE, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == VT_UNKNOWN, "Unexpected vt %d\n", V_VT(&v)); + ok(Provider_child.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + + hr = IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IUIAutomationElement, (void **)&element2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!element2, "element2 == NULL\n"); + VariantClear(&v); + + /* Non-empty bounding rectangle, will return a VT_R8 SAFEARRAY. */ + set_uia_rect(&uia_rect, 0, 0, 50, 50); + Provider_child.bounds_rect = uia_rect; + hr = IUIAutomationElement_GetCurrentPropertyValueEx(element2, UIA_BoundingRectanglePropertyId, TRUE, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_uia_rect_val(&v, &uia_rect); + VariantClear(&v); + ok_method_sequence(get_bounding_rect_seq2, "get_bounding_rect_seq2"); + + hr = IUIAutomationElement_get_CurrentBoundingRectangle(element2, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_uia_rect_rect_val(&rect, &uia_rect); + memset(&rect, 0, sizeof(rect)); + ok_method_sequence(get_bounding_rect_seq3, "get_bounding_rect_seq3"); + + /* Empty bounding rectangle will return ReservedNotSupportedValue. */ + set_uia_rect(&uia_rect, 0, 0, 0, 0); + Provider_child.bounds_rect = uia_rect; + hr = IUIAutomationElement_GetCurrentPropertyValueEx(element2, UIA_BoundingRectanglePropertyId, TRUE, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + 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); + ok_method_sequence(get_empty_bounding_rect_seq, "get_empty_bounding_rect_seq"); + + /* Returns an all 0 rect. */ + hr = IUIAutomationElement_get_CurrentBoundingRectangle(element2, &rect); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + check_uia_rect_rect_val(&rect, &uia_rect); + ok_method_sequence(get_empty_bounding_rect_seq, "get_empty_bounding_rect_seq"); + + IUIAutomationElement_Release(element2); + ok(Provider_child.ref == 1, "Unexpected refcnt %ld\n", Provider_child.ref); + initialize_provider(&Provider_child, ProviderOptions_ServerSideProvider, NULL, FALSE); + +exit: IUIAutomationElement_Release(element); ok(Provider.ref == 1, "Unexpected refcnt %ld\n", Provider.ref);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 8cc39a9342f..b6f308275bb 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -402,8 +402,31 @@ static HRESULT WINAPI uia_element_get_CurrentItemStatus(IUIAutomationElement9 *i
static HRESULT WINAPI uia_element_get_CurrentBoundingRectangle(IUIAutomationElement9 *iface, RECT *ret_val) { - FIXME("%p: stub\n", iface); - return E_NOTIMPL; + struct uia_element *element = impl_from_IUIAutomationElement9(iface); + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", element, ret_val); + + memset(ret_val, 0, sizeof(*ret_val)); + VariantInit(&v); + hr = UiaGetPropertyValue(element->node, UIA_BoundingRectanglePropertyId, &v); + if (SUCCEEDED(hr) && V_VT(&v) == (VT_R8 | VT_ARRAY)) + { + double vals[4]; + LONG idx; + + for (idx = 0; idx < ARRAY_SIZE(vals); idx++) + SafeArrayGetElement(V_ARRAY(&v), &idx, &vals[idx]); + + ret_val->left = vals[0]; + ret_val->top = vals[1]; + ret_val->right = ret_val->left + vals[2]; + ret_val->bottom = ret_val->top + vals[3]; + } + + VariantClear(&v); + return hr; }
static HRESULT WINAPI uia_element_get_CurrentLabeledBy(IUIAutomationElement9 *iface, IUIAutomationElement **ret_val)
V2: Always call `VariantClear` in VARIANTs returned from `UiaGetPropertyValue()`.
Pipeline failure here occurs in the user32 msg tests, so it's unrelated.
This merge request was approved by Esme Povirk.