From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 99 ++++++++++- dlls/uiautomationcore/uia_com_client.c | 194 ++++++++++++++++++++- 2 files changed, 290 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 93929087f2b..0d30ce26f88 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10155,12 +10155,14 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) IUIAutomationConditionInternal *internal_cond; struct UiaPropertyCondition *prop_cond_struct; IUIAutomationPropertyCondition *prop_cond; + IUIAutomationCondition *cond, **cond_arr; enum PropertyConditionFlags prop_flags; IUIAutomationBoolCondition *bool_cond; IUIAutomationNotCondition *not_cond; + IUIAutomationOrCondition *or_cond; struct UiaCondition *cond_struct; - IUIAutomationCondition *cond; PROPERTYID prop_id; + int child_count; BOOL tmp_b; HRESULT hr; VARIANT v; @@ -10390,6 +10392,101 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) IUIAutomationCondition_Release(cond);
IUIAutomationNotCondition_Release(not_cond); + + /* + * IUIAutomationOrCondition tests. + */ + cond = NULL; + VariantInit(&v); + V_VT(&v) = VT_BOOL; + V_BOOL(&v) = VARIANT_FALSE; + hr = IUIAutomation_CreatePropertyCondition(uia_iface, UIA_IsControlElementPropertyId, v, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationPropertyCondition, (void **)&prop_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!prop_cond, "prop_cond == NULL\n"); + + /* NULL input argument tests. */ + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)&ConditionInternal.IUIAutomationConditionInternal_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = (void *)0xdeadbeef; + hr = IUIAutomation_CreateOrCondition(uia_iface, NULL, + (IUIAutomationCondition *)&ConditionInternal.IUIAutomationConditionInternal_iface, &cond); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + cond = (void *)0xdeadbeef; + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, NULL, &cond); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + /* One of the IUIAutomationCondition interfaces are invalid. */ + cond = (void *)0xdeadbeef; + ConditionInternal.return_cond_iface = FALSE; + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)&ConditionInternal.IUIAutomationConditionInternal_iface, &cond); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + cond = NULL; + ConditionInternal.return_cond_iface = TRUE; + SET_EXPECT(ConditionInternal_get_condition_struct); + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)&ConditionInternal.IUIAutomationConditionInternal_iface, &cond); + ok(ConditionInternal.ref == 2, "Unexpected ref %ld", ConditionInternal.ref); + CHECK_CALLED(ConditionInternal_get_condition_struct); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + or_cond = NULL; + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationOrCondition, (void **)&or_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!or_cond, "or_cond == NULL\n"); + + ref = IUIAutomationPropertyCondition_Release(prop_cond); + ok(ref == 1, "Unexpected ref %ld\n", ref); + + hr = IUIAutomationOrCondition_get_ChildCount(or_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + child_count = 0; + hr = IUIAutomationOrCondition_get_ChildCount(or_cond, &child_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(child_count == 2, "Unexpected child_count %d.\n", child_count); + + child_count = 10; + hr = IUIAutomationOrCondition_GetChildrenAsNativeArray(or_cond, NULL, &child_count); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(child_count == 10, "Unexpected child_count %d.\n", child_count); + + cond_arr = (void *)0xdeadbeef; + hr = IUIAutomationOrCondition_GetChildrenAsNativeArray(or_cond, &cond_arr, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!cond_arr, "cond_arr != NULL\n"); + + child_count = 0; + cond_arr = NULL; + hr = IUIAutomationOrCondition_GetChildrenAsNativeArray(or_cond, &cond_arr, &child_count); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(child_count == 2, "Unexpected child_count %d.\n", child_count); + ok(!!cond_arr, "cond_arr == NULL\n"); + + ok(iface_cmp((IUnknown *)cond_arr[0], (IUnknown *)prop_cond), "cond_arr[0] != prop_cond\n"); + IUIAutomationCondition_Release(cond_arr[0]); + + ok(iface_cmp((IUnknown *)cond_arr[1], (IUnknown *)&ConditionInternal.IUIAutomationConditionInternal_iface), + "cond_arr[1] != ConditionInternal\n"); + IUIAutomationCondition_Release(cond_arr[1]); + + CoTaskMemFree(cond_arr); + IUIAutomationOrCondition_Release(or_cond); + ok(ConditionInternal.ref == 1, "Unexpected ref %ld", ConditionInternal.ref); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index c063b7f796a..5bca396ce6b 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -103,6 +103,193 @@ static HRESULT get_uia_condition_struct_from_iface(IUIAutomationCondition *condi return hr; }
+/* + * IUIAutomationOrCondition interface. + */ +struct uia_or_condition { + IUIAutomationOrCondition IUIAutomationOrCondition_iface; + LONG ref; + + IUIAutomationCondition **child_ifaces; + int child_count; + + struct UiaAndOrCondition condition; + struct uia_condition_internal condition_internal; +}; + +static inline struct uia_or_condition *impl_from_IUIAutomationOrCondition(IUIAutomationOrCondition *iface) +{ + return CONTAINING_RECORD(iface, struct uia_or_condition, IUIAutomationOrCondition_iface); +} + +static HRESULT WINAPI uia_or_condition_QueryInterface(IUIAutomationOrCondition *iface, REFIID riid, void **ppv) +{ + struct uia_or_condition *uia_or_condition = impl_from_IUIAutomationOrCondition(iface); + + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomationOrCondition) || IsEqualIID(riid, &IID_IUIAutomationCondition) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else if (IsEqualIID(riid, &IID_IUIAutomationConditionInternal)) + *ppv = &uia_or_condition->condition_internal.IUIAutomationConditionInternal_iface; + else + return E_NOINTERFACE; + + IUIAutomationOrCondition_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_or_condition_AddRef(IUIAutomationOrCondition *iface) +{ + struct uia_or_condition *uia_or_condition = impl_from_IUIAutomationOrCondition(iface); + ULONG ref = InterlockedIncrement(&uia_or_condition->ref); + + TRACE("%p, refcount %ld\n", uia_or_condition, ref); + return ref; +} + +static ULONG WINAPI uia_or_condition_Release(IUIAutomationOrCondition *iface) +{ + struct uia_or_condition *uia_or_condition = impl_from_IUIAutomationOrCondition(iface); + ULONG ref = InterlockedDecrement(&uia_or_condition->ref); + + TRACE("%p, refcount %ld\n", uia_or_condition, ref); + + if (!ref) + { + if (uia_or_condition->child_ifaces) + { + int i; + + for (i = 0; i < uia_or_condition->child_count; i++) + { + if (uia_or_condition->child_ifaces[i]) + IUIAutomationCondition_Release(uia_or_condition->child_ifaces[i]); + } + } + + heap_free(uia_or_condition->child_ifaces); + heap_free(uia_or_condition->condition.ppConditions); + heap_free(uia_or_condition); + } + + return ref; +} + +static HRESULT WINAPI uia_or_condition_get_ChildCount(IUIAutomationOrCondition *iface, int *child_count) +{ + struct uia_or_condition *uia_or_condition = impl_from_IUIAutomationOrCondition(iface); + + TRACE("%p, %p\n", iface, child_count); + + if (!child_count) + return E_POINTER; + + *child_count = uia_or_condition->child_count; + + return S_OK; +} + +static HRESULT WINAPI uia_or_condition_GetChildrenAsNativeArray(IUIAutomationOrCondition *iface, + IUIAutomationCondition ***out_children, int *out_children_count) +{ + struct uia_or_condition *uia_or_condition = impl_from_IUIAutomationOrCondition(iface); + IUIAutomationCondition **children; + int i; + + TRACE("%p, %p, %p\n", iface, out_children, out_children_count); + + if (!out_children) + return E_POINTER; + + *out_children = NULL; + + if (!out_children_count) + return E_POINTER; + + if (!(children = CoTaskMemAlloc(uia_or_condition->child_count * sizeof(*children)))) + return E_OUTOFMEMORY; + + for (i = 0; i < uia_or_condition->child_count; i++) + { + children[i] = uia_or_condition->child_ifaces[i]; + IUIAutomationCondition_AddRef(uia_or_condition->child_ifaces[i]); + } + + *out_children = children; + *out_children_count = uia_or_condition->child_count; + + return S_OK; +} + +static HRESULT WINAPI uia_or_condition_GetChildren(IUIAutomationOrCondition *iface, SAFEARRAY **out_children) +{ + FIXME("%p, %p: stub\n", iface, out_children); + return E_NOTIMPL; +} + +static const IUIAutomationOrConditionVtbl uia_or_condition_vtbl = { + uia_or_condition_QueryInterface, + uia_or_condition_AddRef, + uia_or_condition_Release, + uia_or_condition_get_ChildCount, + uia_or_condition_GetChildrenAsNativeArray, + uia_or_condition_GetChildren, +}; + +static HRESULT create_uia_or_condition_iface(IUIAutomationCondition **out_cond, IUIAutomationCondition **in_conds, + int in_cond_count) +{ + struct uia_or_condition *uia_or_condition; + int i; + + if (!out_cond) + return E_POINTER; + + *out_cond = NULL; + + uia_or_condition = heap_alloc_zero(sizeof(*uia_or_condition)); + if (!uia_or_condition) + return E_OUTOFMEMORY; + + uia_or_condition->IUIAutomationOrCondition_iface.lpVtbl = &uia_or_condition_vtbl; + uia_or_condition->ref = 1; + + uia_or_condition->child_ifaces = heap_alloc_zero(sizeof(*in_conds) * in_cond_count); + if (!uia_or_condition->child_ifaces) + { + IUIAutomationOrCondition_Release(&uia_or_condition->IUIAutomationOrCondition_iface); + return E_OUTOFMEMORY; + } + + uia_or_condition->condition.ppConditions = heap_alloc_zero(sizeof(*uia_or_condition->condition.ppConditions) * in_cond_count); + if (!uia_or_condition->condition.ppConditions) + { + IUIAutomationOrCondition_Release(&uia_or_condition->IUIAutomationOrCondition_iface); + return E_OUTOFMEMORY; + } + + uia_or_condition->condition.ConditionType = ConditionType_Or; + uia_or_condition->child_count = uia_or_condition->condition.cConditions = in_cond_count; + for (i = 0; i < in_cond_count; i++) + { + HRESULT hr; + + hr = get_uia_condition_struct_from_iface(in_conds[i], &uia_or_condition->condition.ppConditions[i]); + if (FAILED(hr)) + { + IUIAutomationOrCondition_Release(&uia_or_condition->IUIAutomationOrCondition_iface); + return hr; + } + + uia_or_condition->child_ifaces[i] = in_conds[i]; + IUIAutomationCondition_AddRef(in_conds[i]); + } + + *out_cond = (IUIAutomationCondition *)&uia_or_condition->IUIAutomationOrCondition_iface; + return S_OK; +} + /* * IUIAutomationNotCondition interface. */ @@ -1707,8 +1894,11 @@ static HRESULT WINAPI uia_iface_CreateAndConditionFromNativeArray(IUIAutomation6 static HRESULT WINAPI uia_iface_CreateOrCondition(IUIAutomation6 *iface, IUIAutomationCondition *cond1, IUIAutomationCondition *cond2, IUIAutomationCondition **out_condition) { - FIXME("%p, %p, %p, %p: stub\n", iface, cond1, cond2, out_condition); - return E_NOTIMPL; + IUIAutomationCondition *cond_arr[2] = { cond1, cond2 }; + + TRACE("%p, %p, %p, %p\n", iface, cond1, cond2, out_condition); + + return create_uia_or_condition_iface(out_condition, cond_arr, ARRAY_SIZE(cond_arr)); }
static HRESULT WINAPI uia_iface_CreateOrConditionFromArray(IUIAutomation6 *iface, SAFEARRAY *conds,