From 6b4ad50c83f01d7ae3775828353c2ac97117f415 Mon Sep 17 00:00:00 2001
From: Connor McAdams <cmcadams@codeweavers.com>
Date: Mon, 6 Mar 2023 10:53:44 -0500
Subject: [PATCH] uiautomationcore: Implement
 IUIAutomation::CreatePropertyCondition.

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,
-- 
GitLab