From 29a4e096d76a2e26ff377766c049ddb352751b40 Mon Sep 17 00:00:00 2001
From: Connor McAdams <cmcadams@codeweavers.com>
Date: Tue, 7 Mar 2023 13:41:50 -0500
Subject: [PATCH] uiautomationcore: Implement
 IUIAutomationCacheRequest::AddProperty.

Signed-off-by: Connor McAdams <cmcadams@codeweavers.com>
---
 dlls/uiautomationcore/tests/uiautomation.c | 18 +++++++--
 dlls/uiautomationcore/uia_client.c         | 31 ----------------
 dlls/uiautomationcore/uia_com_client.c     | 43 ++++++++++++++++++++--
 dlls/uiautomationcore/uia_main.c           |  1 -
 dlls/uiautomationcore/uia_private.h        | 31 ++++++++++++++++
 dlls/uiautomationcore/uia_provider.c       |  1 -
 6 files changed, 85 insertions(+), 40 deletions(-)

diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 715629cd8df..41bd168e3c6 100644
--- a/dlls/uiautomationcore/tests/uiautomation.c
+++ b/dlls/uiautomationcore/tests/uiautomation.c
@@ -10839,6 +10839,16 @@ static void test_CUIAutomation_cache_request_iface(IUIAutomation *uia_iface)
     ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
     todo_wine ok(elem_mode == AutomationElementMode_None, "Unexpected element mode %#x\n", elem_mode);
 
+    /*
+     * AddProperty tests.
+     */
+    hr = IUIAutomationCacheRequest_AddProperty(cache_req, UIA_IsContentElementPropertyId);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+
+    /* Invalid property ID. */
+    hr = IUIAutomationCacheRequest_AddProperty(cache_req, 1);
+    ok(hr == E_INVALIDARG, "Unexpected hr %#lx.\n", hr);
+
     IUIAutomationCacheRequest_Release(cache_req);
 }
 
@@ -10849,13 +10859,13 @@ static const struct prov_method_sequence get_elem_cache_seq[] = {
 };
 
 static const struct prov_method_sequence get_cached_prop_val_seq[] = {
-    { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_TODO },
+    { &Provider_child, FRAG_GET_RUNTIME_ID },
     { 0 },
 };
 
 static const struct prov_method_sequence get_cached_prop_val_seq2[] = {
-    { &Provider_child, FRAG_GET_RUNTIME_ID, METHOD_TODO },
-    { &Provider_child, PROV_GET_PROPERTY_VALUE, METHOD_TODO }, /* UIA_IsControlElementPropertyId */
+    { &Provider_child, FRAG_GET_RUNTIME_ID },
+    { &Provider_child, PROV_GET_PROPERTY_VALUE }, /* UIA_IsControlElementPropertyId */
     { 0 },
 };
 
@@ -10963,7 +10973,7 @@ static void test_Element_cache_methods(IUIAutomation *uia_iface)
      * values.
      */
     hr = IUIAutomationCacheRequest_AddProperty(cache_req, UIA_IsControlElementPropertyId);
-    todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
+    ok(hr == S_OK, "Unexpected hr %#lx.\n", hr);
 
     Provider_child.runtime_id[0] = Provider_child.runtime_id[1] = 0xdeadb33f;
     element2 = NULL;
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c
index 4de9dc1919e..195974c25f6 100644
--- a/dlls/uiautomationcore/uia_client.c
+++ b/dlls/uiautomationcore/uia_client.c
@@ -19,42 +19,11 @@
 #include "uia_private.h"
 
 #include "wine/debug.h"
-#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
 
 static const struct UiaCondition UiaFalseCondition = { ConditionType_False };
 
-static BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
-{
-    SIZE_T max_capacity, new_capacity;
-    void *new_elements;
-
-    if (count <= *capacity)
-        return TRUE;
-
-    max_capacity = ~(SIZE_T)0 / size;
-    if (count > max_capacity)
-        return FALSE;
-
-    new_capacity = max(1, *capacity);
-    while (new_capacity < count && new_capacity <= max_capacity / 2)
-        new_capacity *= 2;
-    if (new_capacity < count)
-        new_capacity = count;
-
-    if (!*elements)
-        new_elements = heap_alloc_zero(new_capacity * size);
-    else
-        new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
-    if (!new_elements)
-        return FALSE;
-
-    *elements = new_elements;
-    *capacity = new_capacity;
-    return TRUE;
-}
-
 struct uia_node_array {
     HUIANODE *nodes;
     int node_count;
diff --git a/dlls/uiautomationcore/uia_com_client.c b/dlls/uiautomationcore/uia_com_client.c
index 44d715684c1..2b499fa8bc5 100644
--- a/dlls/uiautomationcore/uia_com_client.c
+++ b/dlls/uiautomationcore/uia_com_client.c
@@ -19,7 +19,6 @@
 #include "uia_private.h"
 
 #include "wine/debug.h"
-#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
 
@@ -632,6 +631,10 @@ struct uia_cache_request {
 
     IUIAutomationCondition *view_condition;
     struct UiaCacheRequest cache_req;
+
+    int *prop_ids;
+    int prop_ids_count;
+    SIZE_T prop_ids_arr_size;
 };
 
 static inline struct uia_cache_request *impl_from_IUIAutomationCacheRequest(IUIAutomationCacheRequest *iface)
@@ -670,6 +673,7 @@ static ULONG WINAPI uia_cache_request_Release(IUIAutomationCacheRequest *iface)
     if (!ref)
     {
         IUIAutomationCondition_Release(uia_cache_request->view_condition);
+        heap_free(uia_cache_request->prop_ids);
         heap_free(uia_cache_request);
     }
 
@@ -678,8 +682,33 @@ static ULONG WINAPI uia_cache_request_Release(IUIAutomationCacheRequest *iface)
 
 static HRESULT WINAPI uia_cache_request_AddProperty(IUIAutomationCacheRequest *iface, PROPERTYID prop_id)
 {
-    FIXME("%p, %d: stub\n", iface, prop_id);
-    return E_NOTIMPL;
+    struct uia_cache_request *uia_cache_request = impl_from_IUIAutomationCacheRequest(iface);
+    const struct uia_prop_info *prop_info = uia_prop_info_from_id(prop_id);
+    int i;
+
+    TRACE("%p, %d\n", iface, prop_id);
+
+    if (!prop_info)
+        return E_INVALIDARG;
+
+    /* Don't add a duplicate property to the cache request. */
+    for (i = 0; i < uia_cache_request->prop_ids_count; i++)
+    {
+        if (uia_cache_request->prop_ids[i] == prop_id)
+            return S_OK;
+    }
+
+    if (!uia_array_reserve((void **)&uia_cache_request->prop_ids, &uia_cache_request->prop_ids_arr_size,
+                uia_cache_request->prop_ids_count + 1, sizeof(*uia_cache_request->prop_ids)))
+        return E_OUTOFMEMORY;
+
+    uia_cache_request->prop_ids[uia_cache_request->prop_ids_count] = prop_id;
+    uia_cache_request->prop_ids_count++;
+
+    uia_cache_request->cache_req.pProperties = uia_cache_request->prop_ids;
+    uia_cache_request->cache_req.cProperties = uia_cache_request->prop_ids_count;
+
+    return S_OK;
 }
 
 static HRESULT WINAPI uia_cache_request_AddPattern(IUIAutomationCacheRequest *iface, PATTERNID pattern_id)
@@ -847,6 +876,14 @@ static HRESULT create_uia_cache_request_iface(IUIAutomationCacheRequest **out_ca
     uia_cache_request->cache_req.Scope = TreeScope_Element;
     uia_cache_request->cache_req.automationElementMode = AutomationElementMode_Full;
 
+    hr = IUIAutomationCacheRequest_AddProperty(&uia_cache_request->IUIAutomationCacheRequest_iface,
+            UIA_RuntimeIdPropertyId);
+    if (FAILED(hr))
+    {
+        IUIAutomationCacheRequest_Release(&uia_cache_request->IUIAutomationCacheRequest_iface);
+        return hr;
+    }
+
     *out_cache_req = &uia_cache_request->IUIAutomationCacheRequest_iface;
     return S_OK;
 }
diff --git a/dlls/uiautomationcore/uia_main.c b/dlls/uiautomationcore/uia_main.c
index aa297983867..d0ab909f102 100644
--- a/dlls/uiautomationcore/uia_main.c
+++ b/dlls/uiautomationcore/uia_main.c
@@ -23,7 +23,6 @@
 #include "uia_private.h"
 
 #include "wine/debug.h"
-#include "wine/heap.h"
 
 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
 
diff --git a/dlls/uiautomationcore/uia_private.h b/dlls/uiautomationcore/uia_private.h
index 2c6e41eac6d..f7e991ee4fd 100644
--- a/dlls/uiautomationcore/uia_private.h
+++ b/dlls/uiautomationcore/uia_private.h
@@ -21,6 +21,7 @@
 #include "uiautomation.h"
 #include "uia_classes.h"
 #include "wine/list.h"
+#include "wine/heap.h"
 
 extern HMODULE huia_module DECLSPEC_HIDDEN;
 
@@ -98,6 +99,36 @@ static inline void variant_init_bool(VARIANT *v, BOOL val)
     V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE;
 }
 
+static inline BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
+{
+    SIZE_T max_capacity, new_capacity;
+    void *new_elements;
+
+    if (count <= *capacity)
+        return TRUE;
+
+    max_capacity = ~(SIZE_T)0 / size;
+    if (count > max_capacity)
+        return FALSE;
+
+    new_capacity = max(1, *capacity);
+    while (new_capacity < count && new_capacity <= max_capacity / 2)
+        new_capacity *= 2;
+    if (new_capacity < count)
+        new_capacity = count;
+
+    if (!*elements)
+        new_elements = heap_alloc_zero(new_capacity * size);
+    else
+        new_elements = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, *elements, new_capacity * size);
+    if (!new_elements)
+        return FALSE;
+
+    *elements = new_elements;
+    *capacity = new_capacity;
+    return TRUE;
+}
+
 /* 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;
diff --git a/dlls/uiautomationcore/uia_provider.c b/dlls/uiautomationcore/uia_provider.c
index 58d1db9bae8..a7d41248abc 100644
--- a/dlls/uiautomationcore/uia_provider.c
+++ b/dlls/uiautomationcore/uia_provider.c
@@ -20,7 +20,6 @@
 #include "ocidl.h"
 
 #include "wine/debug.h"
-#include "wine/heap.h"
 #include "wine/rbtree.h"
 #include "initguid.h"
 #include "wine/iaccessible2.h"
-- 
GitLab