Module: wine Branch: master Commit: 0b487338f373b41aeeaed76a531262db9f4b1b72 URL: https://gitlab.winehq.org/wine/wine/-/commit/0b487338f373b41aeeaed76a531262d...
Author: Connor McAdams cmcadams@codeweavers.com Date: Thu Feb 2 16:37:43 2023 -0500
uiautomationcore: Implement IUIAutomationElement::get_CurrentControlType.
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;