diff --git a/dlls/uiautomationcore/tests/uiautomation.c b/dlls/uiautomationcore/tests/uiautomation.c
index 715629cd8df8289ef24aedb45625b63bf519ed4c..41bd168e3c6089ef9f398cea4134c081b36b5bf3 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 4de9dc1919e71dc7d140701f45445f2d72a297fd..195974c25f66a88ff7972237855209a121eca42c 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 44d715684c1785e47fd77c330e4cfdc9b7b2847b..2b499fa8bc57a65f5971944821621cb53a85f95f 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 aa2979838670133601ee8b90eeaf52b2222200e8..d0ab909f1021e7db55a3eed1a2bf89b2dbe48691 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 2c6e41eac6d2c5fa1a7ba25eff85f18be00134fc..f7e991ee4fdc727ec706724c19075afc45f55d6b 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 58d1db9bae8ba921d7f97c3c95a8f3f962f0eabd..a7d41248abc5d8a4dc250dc2fb3b1e6e4f3b8a58 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"