-- v3: uiautomationcore: Implement IUIAutomation::CheckNotSupported. uiautomationcore: Implement IUIAutomation reserved value retrieval methods. uiautomationcore: Implement IUIAutomation::IntNativeArrayToSafeArray.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 86 ++++++++++------------ 1 file changed, 37 insertions(+), 49 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 73b0db3073c..1aa22239602 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -5682,40 +5682,15 @@ static void test_UiaGetRuntimeId(void) CoUninitialize(); }
-static LONG Object_ref = 1; -static HRESULT WINAPI Object_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) -{ - *ppv = NULL; - if (IsEqualIID(riid, &IID_IUnknown)) - { - *ppv = iface; - IUnknown_AddRef(iface); - return S_OK; - } - - return E_NOINTERFACE; -} - -static ULONG WINAPI Object_AddRef(IUnknown *iface) -{ - return InterlockedIncrement(&Object_ref); -} - -static ULONG WINAPI Object_Release(IUnknown *iface) -{ - return InterlockedDecrement(&Object_ref); -} - -static IUnknownVtbl ObjectVtbl = { - Object_QueryInterface, - Object_AddRef, - Object_Release +static const struct prov_method_sequence node_from_var_seq[] = { + NODE_CREATE_SEQ(&Provider), + { 0 }, };
-static IUnknown Object = {&ObjectVtbl}; static void test_UiaHUiaNodeFromVariant(void) { - HUIANODE node; + HUIANODE node, node2; + ULONG node_ref; HRESULT hr; VARIANT v;
@@ -5731,44 +5706,57 @@ static void test_UiaHUiaNodeFromVariant(void) ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); ok(!node, "node != NULL\n");
- node = (void *)0xdeadbeef; + node = NULL; + initialize_provider(&Provider, ProviderOptions_ServerSideProvider, NULL, FALSE); + hr = UiaNodeFromProvider(&Provider.IRawElementProviderSimple_iface, &node); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(!!node, "node == NULL\n"); + ok_method_sequence(node_from_var_seq, "node_from_var_seq"); + + node2 = (void *)0xdeadbeef; V_VT(&v) = VT_UNKNOWN; - V_UNKNOWN(&v) = &Object; - hr = UiaHUiaNodeFromVariant(&v, &node); + V_UNKNOWN(&v) = (IUnknown *)node; + hr = UiaHUiaNodeFromVariant(&v, &node2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(node == (void *)&Object, "node != NULL\n"); - ok(Object_ref == 2, "Unexpected Object_ref %ld\n", Object_ref); + ok(node == node2, "node != NULL\n"); + + node_ref = IUnknown_AddRef((IUnknown *)node); + ok(node_ref == 3, "Unexpected node_ref %ld\n", node_ref); VariantClear(&v); + IUnknown_Release((IUnknown *)node);
#ifdef _WIN64 - node = (void *)0xdeadbeef; + node2 = (void *)0xdeadbeef; V_VT(&v) = VT_I4; V_I4(&v) = 0xbeefdead; - hr = UiaHUiaNodeFromVariant(&v, &node); + hr = UiaHUiaNodeFromVariant(&v, &node2); ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - ok(!node, "node != NULL\n"); + ok(!node2, "node2 != NULL\n");
- node = (void *)0xdeadbeef; + node2 = (void *)0xdeadbeef; V_VT(&v) = VT_I8; - V_I8(&v) = 0xbeefdead; - hr = UiaHUiaNodeFromVariant(&v, &node); + V_I8(&v) = (UINT64)node; + hr = UiaHUiaNodeFromVariant(&v, &node2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(node == (void *)V_I8(&v), "node != V_I8\n"); + ok(node2 == (void *)V_I8(&v), "node2 != V_I8\n"); #else - node = (void *)0xdeadbeef; + node2 = (void *)0xdeadbeef; V_VT(&v) = VT_I8; V_I8(&v) = 0xbeefdead; - hr = UiaHUiaNodeFromVariant(&v, &node); + hr = UiaHUiaNodeFromVariant(&v, &node2); ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); - ok(!node, "node != NULL\n"); + ok(!node2, "node2 != NULL\n");
- node = (void *)0xdeadbeef; + node2 = (void *)0xdeadbeef; V_VT(&v) = VT_I4; - V_I4(&v) = 0xbeefdead; - hr = UiaHUiaNodeFromVariant(&v, &node); + V_I4(&v) = (UINT32)node; + hr = UiaHUiaNodeFromVariant(&v, &node2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(node == (void *)V_I4(&v), "node != V_I8\n"); + ok(node2 == (void *)V_I4(&v), "node2 != V_I4\n"); #endif + + UiaNodeRelease(node); }
static const struct prov_method_sequence node_from_hwnd1[] = {
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 49 ++++++++++++++-------- 1 file changed, 31 insertions(+), 18 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1aa22239602..872f2b5950b 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -1261,6 +1261,12 @@ static struct prov_method_sequence *sequence; { prov , FRAG_NAVIGATE }, /* NavigateDirection_Parent */ \ { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \
+#define NODE_CREATE_SEQ2_OPTIONAL(prov) \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, \ + { prov , PROV_GET_HOST_RAW_ELEMENT_PROVIDER, METHOD_OPTIONAL }, \ + { prov , FRAG_NAVIGATE, METHOD_OPTIONAL }, /* NavigateDirection_Parent */ \ + { prov , PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL } \ + static void flush_method_sequence(void) { HeapFree(GetProcessHeap(), 0, sequence); @@ -5780,13 +5786,13 @@ static const struct prov_method_sequence node_from_hwnd2[] = { };
static const struct prov_method_sequence node_from_hwnd3[] = { + NODE_CREATE_SEQ2(&Provider), { &Provider, PROV_GET_PROVIDER_OPTIONS }, - /* Win10v1507 and below call this. */ - { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win11+ */ + /* Windows 11 sends WM_GETOBJECT twice on nested nodes. */ + NODE_CREATE_SEQ2_OPTIONAL(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } }; @@ -5865,18 +5871,19 @@ static const struct prov_method_sequence node_from_hwnd7[] = { { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ { &Provider, PROV_GET_PROVIDER_OPTIONS }, { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win11+ */ { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ProviderDescriptionPropertyId */ { 0 } };
static const struct prov_method_sequence node_from_hwnd8[] = { + NODE_CREATE_SEQ2(&Provider), { &Provider, PROV_GET_PROVIDER_OPTIONS }, - /* Win10v1507 and below call this. */ - { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_OPTIONAL }, /* UIA_NativeWindowHandlePropertyId */ - { &Provider, PROV_GET_HOST_RAW_ELEMENT_PROVIDER }, - { &Provider, FRAG_NAVIGATE }, /* NavigateDirection_Parent */ - { &Provider, PROV_GET_PROVIDER_OPTIONS }, - { &Provider, PROV_GET_PROVIDER_OPTIONS }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, /* Only done on Win11+ */ + /* Windows 11 sends WM_GETOBJECT twice on nested nodes. */ + NODE_CREATE_SEQ2_OPTIONAL(&Provider), + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, + { &Provider, PROV_GET_PROVIDER_OPTIONS, METHOD_OPTIONAL }, { &Provider, PROV_GET_PROPERTY_VALUE }, /* UIA_ProviderDescriptionPropertyId */ { &Provider, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_ControlTypePropertyId */ { 0 } @@ -6028,7 +6035,8 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param)
CoInitializeEx(NULL, COINIT_MULTITHREADED);
- SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only sent twice on Windows 11. */ + SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); /* Only sent on Win7. */ SET_EXPECT(winproc_GETOBJECT_CLIENT); prov_root = &Provider.IRawElementProviderSimple_iface; @@ -6040,7 +6048,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Provider.ignore_hwnd_prop = TRUE; hr = UiaNodeFromHandle(hwnd, &node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref >= 2, "Unexpected refcnt %ld\n", Provider.ref); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); called_winproc_GETOBJECT_CLIENT = expect_winproc_GETOBJECT_CLIENT = 0;
@@ -6190,7 +6198,8 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) /* * UiaDisconnectProvider tests. */ - SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only sent twice on Windows 11. */ + SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); prov_root = &Provider.IRawElementProviderSimple_iface; Provider.prov_opts = ProviderOptions_ServerSideProvider; Provider.hwnd = hwnd; @@ -6200,7 +6209,7 @@ static DWORD WINAPI uia_node_from_handle_test_thread(LPVOID param) Provider.prov_opts = ProviderOptions_ServerSideProvider; hr = UiaNodeFromHandle(hwnd, &node); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); - ok(Provider.ref == 2, "Unexpected refcnt %ld\n", Provider.ref); + ok(Provider.ref >= 2, "Unexpected refcnt %ld\n", Provider.ref); CHECK_CALLED(winproc_GETOBJECT_UiaRoot);
hr = UiaGetPropertyValue(node, UIA_ProviderDescriptionPropertyId, &v); @@ -6378,9 +6387,12 @@ static void test_UiaNodeFromHandle(const char *name) /* Only sent twice on Win7. */ SET_EXPECT_MULTI(winproc_GETOBJECT_CLIENT, 2); hr = UiaNodeFromHandle(hwnd, &node); - todo_wine ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + /* Windows 10 and below return E_FAIL, Windows 11 returns S_OK. */ + todo_wine ok(hr == S_OK || broken(hr == E_FAIL), "Unexpected hr %#lx.\n", hr); CHECK_CALLED(winproc_GETOBJECT_UiaRoot); todo_wine CHECK_CALLED(winproc_GETOBJECT_CLIENT); + if (SUCCEEDED(hr)) + UiaNodeRelease(node);
/* * COM initialized, no provider returned by UiaReturnRawElementProvider. @@ -6610,7 +6622,8 @@ static void test_UiaNodeFromHandle(const char *name) sprintf(cmdline, ""%s" uiautomation UiaNodeFromHandle_client_proc", name); memset(&startup, 0, sizeof(startup)); startup.cb = sizeof(startup); - SET_EXPECT(winproc_GETOBJECT_UiaRoot); + /* Only called twice on Windows 11. */ + SET_EXPECT_MULTI(winproc_GETOBJECT_UiaRoot, 2); /* Only sent on Win7. */ SET_EXPECT(winproc_GETOBJECT_CLIENT); CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &startup, &proc);
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 36 ++++++++++++++++++ dlls/uiautomationcore/uia_client.c | 2 +- dlls/uiautomationcore/uia_com_client.c | 44 +++++++++++++++++++++- dlls/uiautomationcore/uia_private.h | 1 + 4 files changed, 80 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 872f2b5950b..d5cfccf729f 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10014,6 +10014,41 @@ exit: UnregisterClassA("test_Element_GetPropertyValue class", NULL); }
+static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface) +{ + static const VARTYPE invalid_int_vts[] = { VT_I8, VT_INT }; + int *out_arr, out_arr_count, i; + SAFEARRAY *sa; + VARTYPE vt; + HRESULT hr; + + for (i = 0; i < ARRAY_SIZE(invalid_int_vts); i++) + { + vt = invalid_int_vts[i]; + sa = SafeArrayCreateVector(vt, 0, 2); + ok(!!sa, "sa == NULL\n"); + + out_arr_count = 0xdeadbeef; + out_arr = (int *)0xdeadbeef; + hr = IUIAutomation_IntSafeArrayToNativeArray(uia_iface, sa, &out_arr, &out_arr_count); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!out_arr, "out_arr != NULL\n"); + ok(out_arr_count == 0xdeadbeef, "Unexpected out_arr_count %#x\n", out_arr_count); + SafeArrayDestroy(sa); + } + + /* Only accepts VT_I4 as an input array type. */ + sa = create_i4_safearray(); + hr = IUIAutomation_IntSafeArrayToNativeArray(uia_iface, sa, &out_arr, &out_arr_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(out_arr_count == ARRAY_SIZE(uia_i4_arr_prop_val), "Unexpected out_arr_count %#x\n", out_arr_count); + for (i = 0; i < ARRAY_SIZE(uia_i4_arr_prop_val); i++) + ok(out_arr[i] == uia_i4_arr_prop_val[i], "out_arr[%d]: Expected %ld, got %d\n", i, uia_i4_arr_prop_val[i], out_arr[i]); + + SafeArrayDestroy(sa); + CoTaskMemFree(out_arr); +} + struct uia_com_classes { const GUID *clsid; const GUID *iid; @@ -10077,6 +10112,7 @@ static void test_CUIAutomation(void) ok(hr == S_OK, "Failed to create IUIAutomation interface, hr %#lx\n", hr); ok(!!uia_iface, "uia_iface == NULL\n");
+ test_CUIAutomation_value_conversion(uia_iface); test_ElementFromHandle(uia_iface, has_cui8); test_Element_GetPropertyValue(uia_iface);
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index ce2aeb21622..8d543bd4dc7 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -107,7 +107,7 @@ static HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, L return S_OK; }
-static HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) +HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) { UINT dims;
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index b6f308275bb..e78fc4ee416 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1373,8 +1373,48 @@ static HRESULT WINAPI uia_iface_IntNativeArrayToSafeArray(IUIAutomation6 *iface, static HRESULT WINAPI uia_iface_IntSafeArrayToNativeArray(IUIAutomation6 *iface, SAFEARRAY *sa, int **out_arr, int *out_arr_count) { - FIXME("%p, %p, %p, %p: stub\n", iface, sa, out_arr, out_arr_count); - return E_NOTIMPL; + LONG lbound, elems; + int *arr, *sa_arr; + VARTYPE vt; + HRESULT hr; + + TRACE("%p, %p, %p, %p\n", iface, sa, out_arr, out_arr_count); + + if (!sa || !out_arr || !out_arr_count) + return E_INVALIDARG; + + *out_arr = NULL; + hr = SafeArrayGetVartype(sa, &vt); + if (FAILED(hr)) + return hr; + + if (vt != VT_I4) + return E_INVALIDARG; + + hr = get_safearray_bounds(sa, &lbound, &elems); + if (FAILED(hr)) + return hr; + + if (!(arr = CoTaskMemAlloc(elems * sizeof(*arr)))) + return E_OUTOFMEMORY; + + hr = SafeArrayAccessData(sa, (void **)&sa_arr); + if (FAILED(hr)) + goto exit; + + memcpy(arr, sa_arr, sizeof(*arr) * elems); + hr = SafeArrayUnaccessData(sa); + if (FAILED(hr)) + goto exit; + + *out_arr = arr; + *out_arr_count = elems; + +exit: + if (FAILED(hr)) + CoTaskMemFree(arr); + + return hr; }
static HRESULT WINAPI uia_iface_RectToVariant(IUIAutomation6 *iface, RECT rect, VARIANT *out_var) diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h index 157ae3583f8..2c6e41eac6d 100644 --- a/dlls/uiautomationcore/uia_private.h +++ b/dlls/uiautomationcore/uia_private.h @@ -99,6 +99,7 @@ static inline void variant_init_bool(VARIANT *v, BOOL val) }
/* uia_client.c */ +HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) DECLSPEC_HIDDEN; int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type) DECLSPEC_HIDDEN; int get_node_provider_type_at_idx(struct uia_node *node, int idx) DECLSPEC_HIDDEN; HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 40 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 29 ++++++++++++++-- 2 files changed, 67 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index d5cfccf729f..1752682a5a7 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10017,11 +10017,17 @@ exit: static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface) { static const VARTYPE invalid_int_vts[] = { VT_I8, VT_INT }; + int in_arr[3] = { 0xdeadbeef, 0xfeedbeef, 0x1337b33f }; int *out_arr, out_arr_count, i; + LONG lbound, ubound; SAFEARRAY *sa; VARTYPE vt; HRESULT hr; + UINT dims;
+ /* + * Conversion from VT_I4 SAFEARRAY to native int array. + */ for (i = 0; i < ARRAY_SIZE(invalid_int_vts); i++) { vt = invalid_int_vts[i]; @@ -10047,6 +10053,40 @@ static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface)
SafeArrayDestroy(sa); CoTaskMemFree(out_arr); + + /* + * Conversion from native int array to VT_I4 SAFEARRAY. + */ + sa = NULL; + hr = IUIAutomation_IntNativeArrayToSafeArray(uia_iface, in_arr, ARRAY_SIZE(in_arr), &sa); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = SafeArrayGetVartype(sa, &vt); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(vt == VT_I4, "Unexpected vt %d.\n", vt); + + dims = SafeArrayGetDim(sa); + ok(dims == 1, "Unexpected array dims %d\n", dims); + + hr = SafeArrayGetLBound(sa, 1, &lbound); + ok(hr == S_OK, "Failed to get LBound with hr %#lx\n", hr); + ok(lbound == 0, "Unexpected LBound %#lx\n", lbound); + + hr = SafeArrayGetUBound(sa, 1, &ubound); + ok(hr == S_OK, "Failed to get UBound with hr %#lx\n", hr); + ok(((ubound - lbound) + 1) == ARRAY_SIZE(in_arr), "Unexpected array size %#lx\n", ((ubound - lbound) + 1)); + + for (i = 0; i < ARRAY_SIZE(in_arr); i++) + { + LONG idx = lbound + i; + int tmp_val; + + hr = SafeArrayGetElement(sa, &idx, &tmp_val); + ok(hr == S_OK, "Failed to get element at idx %ld, hr %#lx\n", idx, hr); + ok(tmp_val == in_arr[i], "Expected %d at idx %d, got %d\n", in_arr[i], i, tmp_val); + } + + SafeArrayDestroy(sa); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index e78fc4ee416..de01517948a 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1366,8 +1366,33 @@ static HRESULT WINAPI uia_iface_RemoveAllEventHandlers(IUIAutomation6 *iface) static HRESULT WINAPI uia_iface_IntNativeArrayToSafeArray(IUIAutomation6 *iface, int *arr, int arr_count, SAFEARRAY **out_sa) { - FIXME("%p, %p, %d, %p: stub\n", iface, arr, arr_count, out_sa); - return E_NOTIMPL; + HRESULT hr = S_OK; + SAFEARRAY *sa; + int *sa_arr; + + TRACE("%p, %p, %d, %p\n", iface, arr, arr_count, out_sa); + + if (!out_sa || !arr || !arr_count) + return E_INVALIDARG; + + *out_sa = NULL; + if (!(sa = SafeArrayCreateVector(VT_I4, 0, arr_count))) + return E_OUTOFMEMORY; + + hr = SafeArrayAccessData(sa, (void **)&sa_arr); + if (FAILED(hr)) + goto exit; + + memcpy(sa_arr, arr, sizeof(*arr) * arr_count); + hr = SafeArrayUnaccessData(sa); + if (SUCCEEDED(hr)) + *out_sa = sa; + +exit: + if (FAILED(hr)) + SafeArrayDestroy(sa); + + return hr; }
static HRESULT WINAPI uia_iface_IntSafeArrayToNativeArray(IUIAutomation6 *iface, SAFEARRAY *sa, int **out_arr,
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 | 10 ++++++---- 2 files changed, 26 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 1752682a5a7..c2982174463 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10109,6 +10109,7 @@ static const struct uia_com_classes com_classes[] = { static void test_CUIAutomation(void) { IUIAutomation *uia_iface; + IUnknown *unk1, *unk2; BOOL has_cui8 = TRUE; HRESULT hr; int i; @@ -10152,6 +10153,25 @@ static void test_CUIAutomation(void) ok(hr == S_OK, "Failed to create IUIAutomation interface, hr %#lx\n", hr); ok(!!uia_iface, "uia_iface == NULL\n");
+ /* Reserved value retrieval methods. */ + hr = UiaGetReservedNotSupportedValue(&unk1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IUIAutomation_get_ReservedNotSupportedValue(uia_iface, &unk2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(unk1 == unk2, "unk1 != unk2\n"); + IUnknown_Release(unk1); + IUnknown_Release(unk2); + + hr = UiaGetReservedMixedAttributeValue(&unk1); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + hr = IUIAutomation_get_ReservedMixedAttributeValue(uia_iface, &unk2); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(unk1 == unk2, "unk1 != unk2\n"); + IUnknown_Release(unk1); + IUnknown_Release(unk2); + test_CUIAutomation_value_conversion(uia_iface); test_ElementFromHandle(uia_iface, has_cui8); test_Element_GetPropertyValue(uia_iface); diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index de01517948a..33a1967e489 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1509,14 +1509,16 @@ static HRESULT WINAPI uia_iface_CheckNotSupported(IUIAutomation6 *iface, VARIANT
static HRESULT WINAPI uia_iface_get_ReservedNotSupportedValue(IUIAutomation6 *iface, IUnknown **out_unk) { - FIXME("%p, %p: stub\n", iface, out_unk); - return E_NOTIMPL; + TRACE("%p, %p\n", iface, out_unk); + + return UiaGetReservedNotSupportedValue(out_unk); }
static HRESULT WINAPI uia_iface_get_ReservedMixedAttributeValue(IUIAutomation6 *iface, IUnknown **out_unk) { - FIXME("%p, %p: stub\n", iface, out_unk); - return E_NOTIMPL; + TRACE("%p, %p\n", iface, out_unk); + + return UiaGetReservedMixedAttributeValue(out_unk); }
static HRESULT WINAPI uia_iface_ElementFromIAccessible(IUIAutomation6 *iface, IAccessible *acc, int cid,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 17 ++++++++++++++++- dlls/uiautomationcore/uia_com_client.c | 12 ++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index c2982174463..b33a09d4f11 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10108,10 +10108,11 @@ static const struct uia_com_classes com_classes[] = {
static void test_CUIAutomation(void) { + BOOL has_cui8 = TRUE, tmp_b; IUIAutomation *uia_iface; IUnknown *unk1, *unk2; - BOOL has_cui8 = TRUE; HRESULT hr; + VARIANT v; int i;
CoInitializeEx(NULL, COINIT_MULTITHREADED); @@ -10160,6 +10161,13 @@ static void test_CUIAutomation(void) hr = IUIAutomation_get_ReservedNotSupportedValue(uia_iface, &unk2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(unk1 == unk2, "unk1 != unk2\n"); + + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = unk1; + hr = IUIAutomation_CheckNotSupported(uia_iface, v, &tmp_b); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_b == TRUE, "tmp_b != TRUE\n"); + IUnknown_Release(unk1); IUnknown_Release(unk2);
@@ -10169,6 +10177,13 @@ static void test_CUIAutomation(void) hr = IUIAutomation_get_ReservedMixedAttributeValue(uia_iface, &unk2); ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(unk1 == unk2, "unk1 != unk2\n"); + + V_VT(&v) = VT_UNKNOWN; + V_UNKNOWN(&v) = unk1; + hr = IUIAutomation_CheckNotSupported(uia_iface, v, &tmp_b); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_b == FALSE, "tmp_b != FALSE\n"); + IUnknown_Release(unk1); IUnknown_Release(unk2);
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 33a1967e489..f8fdfaa6505 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1503,8 +1503,16 @@ static HRESULT WINAPI uia_iface_PollForPotentialSupportedProperties(IUIAutomatio
static HRESULT WINAPI uia_iface_CheckNotSupported(IUIAutomation6 *iface, VARIANT in_val, BOOL *match) { - FIXME("%p, %s, %p: stub\n", iface, debugstr_variant(&in_val), match); - return E_NOTIMPL; + IUnknown *unk; + + TRACE("%p, %s, %p\n", iface, debugstr_variant(&in_val), match); + + *match = FALSE; + UiaGetReservedNotSupportedValue(&unk); + if (V_VT(&in_val) == VT_UNKNOWN && (V_UNKNOWN(&in_val) == unk)) + *match = TRUE; + + return S_OK; }
static HRESULT WINAPI uia_iface_get_ReservedNotSupportedValue(IUIAutomation6 *iface, IUnknown **out_unk)
On Fri Feb 24 19:57:35 2023 +0000, Esme Povirk wrote:
I think it would make sense to check `lbound` here.
Yeah, good call. I assume it to always be 0, but if it wasn't for some reason that could cause issues. :) Fixed in the most recent version.
V3: Check LBound of SAFEARRAY returned by IntNativeArrayToSafeArray in tests.
This merge request was approved by Esme Povirk.