Module: wine Branch: master Commit: ba960ed49954dc5c4a48bf71780a02c83dff8c68 URL: https://gitlab.winehq.org/wine/wine/-/commit/ba960ed49954dc5c4a48bf71780a02c...
Author: Connor McAdams cmcadams@codeweavers.com Date: Fri Feb 3 12:37:41 2023 -0500
uiautomationcore: Implement IUIAutomationElement::get_CurrentBoundingRectangle.
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)