-- v4: uiautomationcore: Implement IUIAutomation::get_RawViewCondition. uiautomationcore: Implement IUIAutomation::get_ControlViewCondition. uiautomationcore: Implement IUIAutomation::CreateOrCondition. uiautomationcore: Implement IUIAutomation::CreateNotCondition. uiautomationcore: Implement IUIAutomation::CreatePropertyCondition. uiautomationcore: Implement IUIAutomation::Create{True,False}Condition.
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 53 +++++++++++ dlls/uiautomationcore/uia_com_client.c | 102 ++++++++++++++++++++- 2 files changed, 151 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index b33a09d4f11..cdff9c4b573 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10089,6 +10089,58 @@ static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface) SafeArrayDestroy(sa); }
+static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) +{ + IUIAutomationBoolCondition *bool_cond; + IUIAutomationCondition *cond; + BOOL tmp_b; + HRESULT hr; + + hr = IUIAutomation_CreateTrueCondition(uia_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = NULL; + hr = IUIAutomation_CreateTrueCondition(uia_iface, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationBoolCondition, (void **)&bool_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!bool_cond, "bool_cond == NULL\n"); + + hr = IUIAutomationBoolCondition_get_BooleanValue(bool_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + tmp_b = FALSE; + hr = IUIAutomationBoolCondition_get_BooleanValue(bool_cond, &tmp_b); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_b == TRUE, "tmp_b != TRUE\n"); + IUIAutomationBoolCondition_Release(bool_cond); + + hr = IUIAutomation_CreateFalseCondition(uia_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = NULL; + hr = IUIAutomation_CreateFalseCondition(uia_iface, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationBoolCondition, (void **)&bool_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!bool_cond, "bool_cond == NULL\n"); + + hr = IUIAutomationBoolCondition_get_BooleanValue(bool_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + tmp_b = TRUE; + hr = IUIAutomationBoolCondition_get_BooleanValue(bool_cond, &tmp_b); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_b == FALSE, "tmp_b != FALSE\n"); + IUIAutomationBoolCondition_Release(bool_cond); +} + struct uia_com_classes { const GUID *clsid; const GUID *iid; @@ -10187,6 +10239,7 @@ static void test_CUIAutomation(void) IUnknown_Release(unk1); IUnknown_Release(unk2);
+ test_CUIAutomation_condition_ifaces(uia_iface); 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 f8fdfaa6505..74f10b56f67 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -23,6 +23,98 @@
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+/* + * IUIAutomationBoolCondition interface. + */ +struct uia_bool_condition { + IUIAutomationBoolCondition IUIAutomationBoolCondition_iface; + LONG ref; + + struct UiaCondition condition; +}; + +static inline struct uia_bool_condition *impl_from_IUIAutomationBoolCondition(IUIAutomationBoolCondition *iface) +{ + return CONTAINING_RECORD(iface, struct uia_bool_condition, IUIAutomationBoolCondition_iface); +} + +static HRESULT WINAPI uia_bool_condition_QueryInterface(IUIAutomationBoolCondition *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomationBoolCondition) || IsEqualIID(riid, &IID_IUIAutomationCondition) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomationBoolCondition_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_bool_condition_AddRef(IUIAutomationBoolCondition *iface) +{ + struct uia_bool_condition *uia_bool_condition = impl_from_IUIAutomationBoolCondition(iface); + ULONG ref = InterlockedIncrement(&uia_bool_condition->ref); + + TRACE("%p, refcount %ld\n", uia_bool_condition, ref); + return ref; +} + +static ULONG WINAPI uia_bool_condition_Release(IUIAutomationBoolCondition *iface) +{ + struct uia_bool_condition *uia_bool_condition = impl_from_IUIAutomationBoolCondition(iface); + ULONG ref = InterlockedDecrement(&uia_bool_condition->ref); + + TRACE("%p, refcount %ld\n", uia_bool_condition, ref); + if (!ref) + heap_free(uia_bool_condition); + + return ref; +} + +static HRESULT WINAPI uia_bool_condition_get_BooleanValue(IUIAutomationBoolCondition *iface, BOOL *ret_val) +{ + struct uia_bool_condition *uia_bool_condition = impl_from_IUIAutomationBoolCondition(iface); + + TRACE("%p, %p\n", iface, ret_val); + + if (!ret_val) + return E_POINTER; + + if (uia_bool_condition->condition.ConditionType == ConditionType_True) + *ret_val = TRUE; + else + *ret_val = FALSE; + + return S_OK; +} + +static const IUIAutomationBoolConditionVtbl uia_bool_condition_vtbl = { + uia_bool_condition_QueryInterface, + uia_bool_condition_AddRef, + uia_bool_condition_Release, + uia_bool_condition_get_BooleanValue, +}; + +static HRESULT create_uia_bool_condition_iface(IUIAutomationCondition **out_cond, enum ConditionType cond_type) +{ + struct uia_bool_condition *uia_bool_condition; + + if (!out_cond) + return E_POINTER; + + uia_bool_condition = heap_alloc_zero(sizeof(*uia_bool_condition)); + if (!uia_bool_condition) + return E_OUTOFMEMORY; + + uia_bool_condition->IUIAutomationBoolCondition_iface.lpVtbl = &uia_bool_condition_vtbl; + uia_bool_condition->condition.ConditionType = cond_type; + uia_bool_condition->ref = 1; + + *out_cond = (IUIAutomationCondition *)&uia_bool_condition->IUIAutomationBoolCondition_iface; + return S_OK; +} + /* * IUIAutomationElement interface. */ @@ -1217,14 +1309,16 @@ static HRESULT WINAPI uia_iface_CreateCacheRequest(IUIAutomation6 *iface, IUIAut
static HRESULT WINAPI uia_iface_CreateTrueCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) { - FIXME("%p, %p: stub\n", iface, out_condition); - return E_NOTIMPL; + TRACE("%p, %p\n", iface, out_condition); + + return create_uia_bool_condition_iface(out_condition, ConditionType_True); }
static HRESULT WINAPI uia_iface_CreateFalseCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) { - FIXME("%p, %p: stub\n", iface, out_condition); - return E_NOTIMPL; + TRACE("%p, %p\n", iface, out_condition); + + return create_uia_bool_condition_iface(out_condition, ConditionType_False); }
static HRESULT WINAPI uia_iface_CreatePropertyCondition(IUIAutomation6 *iface, PROPERTYID prop_id, VARIANT val,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 64 +++++++++ dlls/uiautomationcore/uia_com_client.c | 155 ++++++++++++++++++++- 2 files changed, 217 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index cdff9c4b573..ea2fda749a1 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10091,10 +10091,14 @@ static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface)
static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) { + IUIAutomationPropertyCondition *prop_cond; + enum PropertyConditionFlags prop_flags; IUIAutomationBoolCondition *bool_cond; IUIAutomationCondition *cond; + PROPERTYID prop_id; BOOL tmp_b; HRESULT hr; + VARIANT v;
hr = IUIAutomation_CreateTrueCondition(uia_iface, NULL); ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); @@ -10139,6 +10143,66 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(tmp_b == FALSE, "tmp_b != FALSE\n"); IUIAutomationBoolCondition_Release(bool_cond); + + /* + * IUIAutomationPropertyCondition tests. + */ + cond = (void *)0xdeadbeef; + VariantInit(&v); + /* Invalid property ID. */ + hr = IUIAutomation_CreatePropertyCondition(uia_iface, 0, v, &cond); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + /* Invalid variant type for property ID. */ + cond = (void *)0xdeadbeef; + VariantInit(&v); + hr = IUIAutomation_CreatePropertyCondition(uia_iface, UIA_RuntimeIdPropertyId, v, &cond); + ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + /* NULL Condition argument. */ + V_VT(&v) = VT_I4 | VT_ARRAY; + V_ARRAY(&v) = create_i4_safearray(); + hr = IUIAutomation_CreatePropertyCondition(uia_iface, UIA_RuntimeIdPropertyId, v, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + /* Finally, create property condition interface. */ + cond = NULL; + hr = IUIAutomation_CreatePropertyCondition(uia_iface, UIA_RuntimeIdPropertyId, 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"); + + hr = IUIAutomationPropertyCondition_get_PropertyId(prop_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IUIAutomationPropertyCondition_get_PropertyId(prop_cond, &prop_id); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prop_id == UIA_RuntimeIdPropertyId, "Unexpected prop_id %d.\n", prop_id); + + hr = IUIAutomationPropertyCondition_get_PropertyValue(prop_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + VariantClear(&v); + hr = IUIAutomationPropertyCondition_get_PropertyValue(prop_cond, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(V_VT(&v) == (VT_I4 | VT_ARRAY), "Unexpected vt %d.\n", V_VT(&v)); + ok(!!V_ARRAY(&v), "V_ARRAY(&v) == NULL\n"); + VariantClear(&v); + + hr = IUIAutomationPropertyCondition_get_PropertyConditionFlags(prop_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + hr = IUIAutomationPropertyCondition_get_PropertyConditionFlags(prop_cond, &prop_flags); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prop_flags == PropertyConditionFlags_None, "Unexpected flags %#x.\n", prop_flags); + + IUIAutomationPropertyCondition_Release(prop_cond); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 74f10b56f67..c593b76e1d8 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -23,6 +23,156 @@
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+/* + * IUIAutomationPropertyCondition interface. + */ +struct uia_property_condition { + IUIAutomationPropertyCondition IUIAutomationPropertyCondition_iface; + LONG ref; + + struct UiaPropertyCondition condition; +}; + +static inline struct uia_property_condition *impl_from_IUIAutomationPropertyCondition(IUIAutomationPropertyCondition *iface) +{ + return CONTAINING_RECORD(iface, struct uia_property_condition, IUIAutomationPropertyCondition_iface); +} + +static HRESULT WINAPI uia_property_condition_QueryInterface(IUIAutomationPropertyCondition *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomationPropertyCondition) || IsEqualIID(riid, &IID_IUIAutomationCondition) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomationPropertyCondition_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_property_condition_AddRef(IUIAutomationPropertyCondition *iface) +{ + struct uia_property_condition *uia_property_condition = impl_from_IUIAutomationPropertyCondition(iface); + ULONG ref = InterlockedIncrement(&uia_property_condition->ref); + + TRACE("%p, refcount %ld\n", uia_property_condition, ref); + return ref; +} + +static ULONG WINAPI uia_property_condition_Release(IUIAutomationPropertyCondition *iface) +{ + struct uia_property_condition *uia_property_condition = impl_from_IUIAutomationPropertyCondition(iface); + ULONG ref = InterlockedDecrement(&uia_property_condition->ref); + + TRACE("%p, refcount %ld\n", uia_property_condition, ref); + + if (!ref) + { + VariantClear(&uia_property_condition->condition.Value); + heap_free(uia_property_condition); + } + + return ref; +} + +static HRESULT WINAPI uia_property_condition_get_PropertyId(IUIAutomationPropertyCondition *iface, PROPERTYID *prop_id) +{ + struct uia_property_condition *uia_property_condition = impl_from_IUIAutomationPropertyCondition(iface); + + TRACE("%p, %p\n", iface, prop_id); + + if (!prop_id) + return E_POINTER; + + *prop_id = uia_property_condition->condition.PropertyId; + + return S_OK; +} + +static HRESULT WINAPI uia_property_condition_get_PropertyValue(IUIAutomationPropertyCondition *iface, VARIANT *val) +{ + struct uia_property_condition *uia_property_condition = impl_from_IUIAutomationPropertyCondition(iface); + + TRACE("%p, %p\n", iface, val); + + if (!val) + return E_POINTER; + + VariantCopy(val, &uia_property_condition->condition.Value); + + return S_OK; +} + +static HRESULT WINAPI uia_property_condition_get_PropertyConditionFlags(IUIAutomationPropertyCondition *iface, + enum PropertyConditionFlags *flags) +{ + struct uia_property_condition *uia_property_condition = impl_from_IUIAutomationPropertyCondition(iface); + + TRACE("%p, %p\n", iface, flags); + + if (!flags) + return E_POINTER; + + *flags = uia_property_condition->condition.Flags; + + return S_OK; +} + +static const IUIAutomationPropertyConditionVtbl uia_property_condition_vtbl = { + uia_property_condition_QueryInterface, + uia_property_condition_AddRef, + uia_property_condition_Release, + uia_property_condition_get_PropertyId, + uia_property_condition_get_PropertyValue, + uia_property_condition_get_PropertyConditionFlags, +}; + +static HRESULT create_uia_property_condition_iface(IUIAutomationCondition **out_cond, PROPERTYID prop_id, VARIANT val, + enum PropertyConditionFlags prop_flags) +{ + const struct uia_prop_info *prop_info = uia_prop_info_from_id(prop_id); + struct uia_property_condition *uia_property_condition; + + if (!out_cond) + return E_POINTER; + + *out_cond = NULL; + if (!prop_info) + return E_INVALIDARG; + + switch (prop_info->type) + { + case UIAutomationType_Bool: + if (V_VT(&val) != VT_BOOL) + return E_INVALIDARG; + break; + + case UIAutomationType_IntArray: + if (V_VT(&val) != (VT_I4 | VT_ARRAY)) + return E_INVALIDARG; + break; + + default: + FIXME("Property condition evaluation for property type %#x unimplemented\n", prop_info->type); + return E_NOTIMPL; + } + + uia_property_condition = heap_alloc_zero(sizeof(*uia_property_condition)); + if (!uia_property_condition) + return E_OUTOFMEMORY; + + uia_property_condition->IUIAutomationPropertyCondition_iface.lpVtbl = &uia_property_condition_vtbl; + uia_property_condition->condition.ConditionType = ConditionType_Property; + uia_property_condition->condition.PropertyId = prop_id; + VariantCopy(&uia_property_condition->condition.Value, &val); + uia_property_condition->condition.Flags = prop_flags; + uia_property_condition->ref = 1; + + *out_cond = (IUIAutomationCondition *)&uia_property_condition->IUIAutomationPropertyCondition_iface; + return S_OK; +} + /* * IUIAutomationBoolCondition interface. */ @@ -1324,8 +1474,9 @@ static HRESULT WINAPI uia_iface_CreateFalseCondition(IUIAutomation6 *iface, IUIA static HRESULT WINAPI uia_iface_CreatePropertyCondition(IUIAutomation6 *iface, PROPERTYID prop_id, VARIANT val, IUIAutomationCondition **out_condition) { - FIXME("%p, %d, %s, %p: stub\n", iface, prop_id, debugstr_variant(&val), out_condition); - return E_NOTIMPL; + TRACE("%p, %d, %s, %p\n", iface, prop_id, debugstr_variant(&val), out_condition); + + return create_uia_property_condition_iface(out_condition, prop_id, val, PropertyConditionFlags_None); }
static HRESULT WINAPI uia_iface_CreatePropertyConditionEx(IUIAutomation6 *iface, PROPERTYID prop_id, VARIANT val,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 78 ++++++++++- dlls/uiautomationcore/uia_com_client.c | 144 ++++++++++++++++++++- 2 files changed, 219 insertions(+), 3 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index ea2fda749a1..34b9df3a329 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10089,16 +10089,46 @@ static void test_CUIAutomation_value_conversion(IUIAutomation *uia_iface) SafeArrayDestroy(sa); }
+static HRESULT WINAPI Object_QueryInterface(IUnknown *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + return S_OK; +} + +static ULONG WINAPI Object_AddRef(IUnknown *iface) +{ + return 2; +} + +static ULONG WINAPI Object_Release(IUnknown *iface) +{ + return 1; +} + +static IUnknownVtbl ObjectVtbl = { + Object_QueryInterface, + Object_AddRef, + Object_Release +}; +static IUnknown Object = {&ObjectVtbl}; + static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) { IUIAutomationPropertyCondition *prop_cond; enum PropertyConditionFlags prop_flags; IUIAutomationBoolCondition *bool_cond; + IUIAutomationNotCondition *not_cond; IUIAutomationCondition *cond; PROPERTYID prop_id; BOOL tmp_b; HRESULT hr; VARIANT v; + ULONG ref;
hr = IUIAutomation_CreateTrueCondition(uia_iface, NULL); ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); @@ -10202,7 +10232,53 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ok(prop_flags == PropertyConditionFlags_None, "Unexpected flags %#x.\n", prop_flags);
- IUIAutomationPropertyCondition_Release(prop_cond); + /* + * IUIAutomationNotCondition tests. + */ + cond = (void *)0xdeadbeef; + + /* + * Passing in an interface that isn't a valid IUIAutomationCondition + * interface. + */ + hr = IUIAutomation_CreateNotCondition(uia_iface, (IUIAutomationCondition *)&Object, &cond); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + /* NULL input argument tests. */ + cond = (void *)0xdeadbeef; + hr = IUIAutomation_CreateNotCondition(uia_iface, NULL, &cond); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + hr = IUIAutomation_CreateNotCondition(uia_iface, (IUIAutomationCondition *)prop_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + /* Create the IUIAutomationNotCondition with our property condition. */ + cond = NULL; + hr = IUIAutomation_CreateNotCondition(uia_iface, (IUIAutomationCondition *)prop_cond, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + /* IUIAutomationNotCondition holds a reference to the passed in condition. */ + ref = IUIAutomationPropertyCondition_Release(prop_cond); + ok(ref == 1, "Unexpected ref %ld\n", ref); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationNotCondition, (void **)¬_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!not_cond, "not_cond == NULL\n"); + + hr = IUIAutomationNotCondition_GetChild(not_cond, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = NULL; + hr = IUIAutomationNotCondition_GetChild(not_cond, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(iface_cmp((IUnknown *)cond, (IUnknown *)prop_cond), "cond != prop_cond\n"); + IUIAutomationCondition_Release(cond); + + IUIAutomationNotCondition_Release(not_cond); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index c593b76e1d8..e4ea54a3aef 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -23,6 +23,112 @@
WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
+static HRESULT get_uia_condition_struct_from_iface(IUIAutomationCondition *condition, struct UiaCondition **cond_struct); + +/* + * IUIAutomationNotCondition interface. + */ +struct uia_not_condition { + IUIAutomationNotCondition IUIAutomationNotCondition_iface; + LONG ref; + + IUIAutomationCondition *child_iface; + struct UiaNotCondition condition; +}; + +static inline struct uia_not_condition *impl_from_IUIAutomationNotCondition(IUIAutomationNotCondition *iface) +{ + return CONTAINING_RECORD(iface, struct uia_not_condition, IUIAutomationNotCondition_iface); +} + +static HRESULT WINAPI uia_not_condition_QueryInterface(IUIAutomationNotCondition *iface, REFIID riid, void **ppv) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomationNotCondition) || IsEqualIID(riid, &IID_IUIAutomationCondition) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = iface; + else + return E_NOINTERFACE; + + IUIAutomationNotCondition_AddRef(iface); + return S_OK; +} + +static ULONG WINAPI uia_not_condition_AddRef(IUIAutomationNotCondition *iface) +{ + struct uia_not_condition *uia_not_condition = impl_from_IUIAutomationNotCondition(iface); + ULONG ref = InterlockedIncrement(&uia_not_condition->ref); + + TRACE("%p, refcount %ld\n", uia_not_condition, ref); + return ref; +} + +static ULONG WINAPI uia_not_condition_Release(IUIAutomationNotCondition *iface) +{ + struct uia_not_condition *uia_not_condition = impl_from_IUIAutomationNotCondition(iface); + ULONG ref = InterlockedDecrement(&uia_not_condition->ref); + + TRACE("%p, refcount %ld\n", uia_not_condition, ref); + if (!ref) + { + IUIAutomationCondition_Release(uia_not_condition->child_iface); + heap_free(uia_not_condition); + } + + return ref; +} + +static HRESULT WINAPI uia_not_condition_GetChild(IUIAutomationNotCondition *iface, IUIAutomationCondition **child) +{ + struct uia_not_condition *uia_not_condition = impl_from_IUIAutomationNotCondition(iface); + + TRACE("%p, %p\n", iface, child); + + if (!child) + return E_POINTER; + + IUIAutomationCondition_AddRef(uia_not_condition->child_iface); + *child = uia_not_condition->child_iface; + + return S_OK; +} + +static const IUIAutomationNotConditionVtbl uia_not_condition_vtbl = { + uia_not_condition_QueryInterface, + uia_not_condition_AddRef, + uia_not_condition_Release, + uia_not_condition_GetChild, +}; + +static HRESULT create_uia_not_condition_iface(IUIAutomationCondition **out_cond, IUIAutomationCondition *in_cond) +{ + struct uia_not_condition *uia_not_condition; + struct UiaCondition *cond_struct; + HRESULT hr; + + if (!out_cond) + return E_POINTER; + + *out_cond = NULL; + hr = get_uia_condition_struct_from_iface(in_cond, &cond_struct); + if (FAILED(hr)) + return hr; + + uia_not_condition = heap_alloc_zero(sizeof(*uia_not_condition)); + if (!uia_not_condition) + return E_OUTOFMEMORY; + + uia_not_condition->IUIAutomationNotCondition_iface.lpVtbl = &uia_not_condition_vtbl; + uia_not_condition->condition.ConditionType = ConditionType_Not; + uia_not_condition->condition.pConditions = cond_struct; + uia_not_condition->ref = 1; + uia_not_condition->child_iface = in_cond; + IUIAutomationCondition_AddRef(in_cond); + + *out_cond = (IUIAutomationCondition *)&uia_not_condition->IUIAutomationNotCondition_iface; + return S_OK; +} + /* * IUIAutomationPropertyCondition interface. */ @@ -265,6 +371,39 @@ static HRESULT create_uia_bool_condition_iface(IUIAutomationCondition **out_cond return S_OK; }
+static HRESULT get_uia_condition_struct_from_iface(IUIAutomationCondition *condition, struct UiaCondition **cond_struct) +{ + *cond_struct = NULL; + if (!condition) + return E_POINTER; + + if (condition->lpVtbl == (IUIAutomationConditionVtbl *)&uia_bool_condition_vtbl) + { + struct uia_bool_condition *cond; + + cond = impl_from_IUIAutomationBoolCondition((IUIAutomationBoolCondition *)condition); + *cond_struct = &cond->condition; + } + else if (condition->lpVtbl == (IUIAutomationConditionVtbl *)&uia_property_condition_vtbl) + { + struct uia_property_condition *cond; + + cond = impl_from_IUIAutomationPropertyCondition((IUIAutomationPropertyCondition *)condition); + *cond_struct = (struct UiaCondition *)&cond->condition; + } + else if (condition->lpVtbl == (IUIAutomationConditionVtbl *)&uia_not_condition_vtbl) + { + struct uia_not_condition *cond; + + cond = impl_from_IUIAutomationNotCondition((IUIAutomationNotCondition *)condition); + *cond_struct = (struct UiaCondition *)&cond->condition; + } + else + return E_FAIL; + + return S_OK; +} + /* * IUIAutomationElement interface. */ @@ -1531,8 +1670,9 @@ static HRESULT WINAPI uia_iface_CreateOrConditionFromNativeArray(IUIAutomation6 static HRESULT WINAPI uia_iface_CreateNotCondition(IUIAutomation6 *iface, IUIAutomationCondition *cond, IUIAutomationCondition **out_condition) { - FIXME("%p, %p, %p: stub\n", iface, cond, out_condition); - return E_NOTIMPL; + TRACE("%p, %p, %p\n", iface, cond, out_condition); + + return create_uia_not_condition_iface(out_condition, cond); }
static HRESULT WINAPI uia_iface_AddAutomationEventHandler(IUIAutomation6 *iface, EVENTID event_id,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 111 +++++++++++- dlls/uiautomationcore/uia_com_client.c | 196 ++++++++++++++++++++- 2 files changed, 303 insertions(+), 4 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index 34b9df3a329..a649140a9a1 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10119,12 +10119,14 @@ static IUnknown Object = {&ObjectVtbl};
static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface) { - IUIAutomationPropertyCondition *prop_cond; + IUIAutomationPropertyCondition *prop_cond, *prop_cond2; + IUIAutomationCondition *cond, **cond_arr; enum PropertyConditionFlags prop_flags; IUIAutomationBoolCondition *bool_cond; IUIAutomationNotCondition *not_cond; - IUIAutomationCondition *cond; + IUIAutomationOrCondition *or_cond; PROPERTYID prop_id; + int child_count; BOOL tmp_b; HRESULT hr; VARIANT v; @@ -10279,6 +10281,111 @@ 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; + /* Create two condition interfaces to use for our IUIAutomationOrCondition. */ + 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"); + + cond = NULL; + VariantInit(&v); + V_VT(&v) = VT_BOOL; + V_BOOL(&v) = VARIANT_TRUE; + hr = IUIAutomation_CreatePropertyCondition(uia_iface, UIA_IsContentElementPropertyId, v, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationPropertyCondition, (void **)&prop_cond2); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!prop_cond2, "prop_cond2 == NULL\n"); + + /* NULL input argument tests. */ + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)prop_cond2, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = (void *)0xdeadbeef; + hr = IUIAutomation_CreateOrCondition(uia_iface, NULL, (IUIAutomationCondition *)prop_cond2, &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; + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)&Object, &cond); + ok(hr == E_FAIL, "Unexpected hr %#lx.\n", hr); + ok(!cond, "cond != NULL\n"); + + cond = NULL; + hr = IUIAutomation_CreateOrCondition(uia_iface, (IUIAutomationCondition *)prop_cond, + (IUIAutomationCondition *)prop_cond2, &cond); + 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"); + + /* References held to both passed in interfaces. */ + ref = IUIAutomationPropertyCondition_Release(prop_cond); + ok(ref == 1, "Unexpected ref %ld\n", ref); + + ref = IUIAutomationPropertyCondition_Release(prop_cond2); + 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 *)prop_cond2), "cond_arr[1] != prop_cond2\n"); + IUIAutomationCondition_Release(cond_arr[1]); + + CoTaskMemFree(cond_arr); + IUIAutomationOrCondition_Release(or_cond); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index e4ea54a3aef..4541a9ddeeb 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -25,6 +25,188 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
static HRESULT get_uia_condition_struct_from_iface(IUIAutomationCondition *condition, struct UiaCondition **cond_struct);
+/* + * IUIAutomationOrCondition interface. + */ +struct uia_or_condition { + IUIAutomationOrCondition IUIAutomationOrCondition_iface; + LONG ref; + + IUIAutomationCondition **child_ifaces; + int child_count; + + struct UiaAndOrCondition condition; +}; + +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) +{ + *ppv = NULL; + if (IsEqualIID(riid, &IID_IUIAutomationOrCondition) || IsEqualIID(riid, &IID_IUIAutomationCondition) || + IsEqualIID(riid, &IID_IUnknown)) + *ppv = 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. */ @@ -398,6 +580,13 @@ static HRESULT get_uia_condition_struct_from_iface(IUIAutomationCondition *condi cond = impl_from_IUIAutomationNotCondition((IUIAutomationNotCondition *)condition); *cond_struct = (struct UiaCondition *)&cond->condition; } + else if (condition->lpVtbl == (IUIAutomationConditionVtbl *)&uia_or_condition_vtbl) + { + struct uia_or_condition *cond; + + cond = impl_from_IUIAutomationOrCondition((IUIAutomationOrCondition *)condition); + *cond_struct = (struct UiaCondition *)&cond->condition; + } else return E_FAIL;
@@ -1649,8 +1838,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,
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 44 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 30 ++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index a649140a9a1..b4d88ca403c 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10386,6 +10386,50 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface)
CoTaskMemFree(cond_arr); IUIAutomationOrCondition_Release(or_cond); + + /* + * Condition used to get the control TreeView. Equivalent to: + * if (!(UIA_IsControlElementPropertyId == VARIANT_FALSE)) + */ + hr = IUIAutomation_get_ControlViewCondition(uia_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = NULL; + hr = IUIAutomation_get_ControlViewCondition(uia_iface, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationNotCondition, (void **)¬_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!not_cond, "not_cond == NULL\n"); + + cond = NULL; + hr = IUIAutomationNotCondition_GetChild(not_cond, &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"); + + hr = IUIAutomationPropertyCondition_get_PropertyId(prop_cond, &prop_id); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prop_id == UIA_IsControlElementPropertyId, "Unexpected prop_id %d.\n", prop_id); + + VariantInit(&v); + hr = IUIAutomationPropertyCondition_get_PropertyValue(prop_cond, &v); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(check_variant_bool(&v, FALSE), "Unexpected BOOL %#x\n", V_BOOL(&v)); + VariantClear(&v); + + hr = IUIAutomationPropertyCondition_get_PropertyConditionFlags(prop_cond, &prop_flags); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(prop_flags == PropertyConditionFlags_None, "Unexpected flags %#x.\n", prop_flags); + + IUIAutomationPropertyCondition_Release(prop_cond); + IUIAutomationNotCondition_Release(not_cond); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 4541a9ddeeb..0c9bd769b9e 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1769,8 +1769,34 @@ static HRESULT WINAPI uia_iface_get_RawViewCondition(IUIAutomation6 *iface, IUIA
static HRESULT WINAPI uia_iface_get_ControlViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) { - FIXME("%p, %p: stub\n", iface, out_condition); - return E_NOTIMPL; + IUIAutomationCondition *prop_cond, *not_cond; + HRESULT hr; + VARIANT v; + + TRACE("%p, %p\n", iface, out_condition); + + if (!out_condition) + return E_POINTER; + + *out_condition = NULL; + + VariantInit(&v); + V_VT(&v) = VT_BOOL; + V_BOOL(&v) = VARIANT_FALSE; + hr = create_uia_property_condition_iface(&prop_cond, UIA_IsControlElementPropertyId, v, PropertyConditionFlags_None); + if (FAILED(hr)) + return hr; + + hr = create_uia_not_condition_iface(¬_cond, prop_cond); + if (FAILED(hr)) + { + IUIAutomationCondition_Release(prop_cond); + return hr; + } + + *out_condition = not_cond; + + return S_OK; }
static HRESULT WINAPI uia_iface_get_ContentViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition)
From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/tests/uiautomation.c | 23 ++++++++++++++++++++++ dlls/uiautomationcore/uia_com_client.c | 5 +++-- 2 files changed, 26 insertions(+), 2 deletions(-)
diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c index b4d88ca403c..e6be0ce75a3 100644 --- a/dlls/uiautomationcore/tests/uiautomation.c +++ b/dlls/uiautomationcore/tests/uiautomation.c @@ -10430,6 +10430,29 @@ static void test_CUIAutomation_condition_ifaces(IUIAutomation *uia_iface)
IUIAutomationPropertyCondition_Release(prop_cond); IUIAutomationNotCondition_Release(not_cond); + + /* + * Condition used to get the raw TreeView. Equivalent to: + * if (1) + */ + hr = IUIAutomation_get_RawViewCondition(uia_iface, NULL); + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + cond = NULL; + hr = IUIAutomation_get_RawViewCondition(uia_iface, &cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!cond, "cond == NULL\n"); + + hr = IUIAutomationCondition_QueryInterface(cond, &IID_IUIAutomationBoolCondition, (void **)&bool_cond); + IUIAutomationCondition_Release(cond); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(!!bool_cond, "bool_cond == NULL\n"); + + tmp_b = FALSE; + hr = IUIAutomationBoolCondition_get_BooleanValue(bool_cond, &tmp_b); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ok(tmp_b == TRUE, "tmp_b != TRUE\n"); + IUIAutomationBoolCondition_Release(bool_cond); }
struct uia_com_classes { diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c index 0c9bd769b9e..a6320f15b0d 100644 --- a/dlls/uiautomationcore/uia_com_client.c +++ b/dlls/uiautomationcore/uia_com_client.c @@ -1763,8 +1763,9 @@ static HRESULT WINAPI uia_iface_get_RawViewWalker(IUIAutomation6 *iface, IUIAuto
static HRESULT WINAPI uia_iface_get_RawViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition) { - FIXME("%p, %p: stub\n", iface, out_condition); - return E_NOTIMPL; + TRACE("%p, %p\n", iface, out_condition); + + return create_uia_bool_condition_iface(out_condition, ConditionType_True); }
static HRESULT WINAPI uia_iface_get_ControlViewCondition(IUIAutomation6 *iface, IUIAutomationCondition **out_condition)
On Fri Mar 3 22:44:44 2023 +0000, Connor McAdams wrote:
Well, given I don't have a strong opinion on keeping this, I'll just redo it without the undocumented interface to avoid any issues.
Switched back to the old method of vtbl checks in the current version.
V4: Remove usage of undocumented interface.
This merge request was approved by Esme Povirk.