From: Connor McAdams cmcadams@codeweavers.com
Signed-off-by: Connor McAdams cmcadams@codeweavers.com --- dlls/uiautomationcore/uia_client.c | 85 ++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 11 deletions(-)
diff --git a/dlls/uiautomationcore/uia_client.c b/dlls/uiautomationcore/uia_client.c index 42795e7218b..715d8b27fbd 100644 --- a/dlls/uiautomationcore/uia_client.c +++ b/dlls/uiautomationcore/uia_client.c @@ -25,6 +25,67 @@ WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
static const struct UiaCondition UiaFalseCondition = { ConditionType_False };
+static BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T element_count, SIZE_T element_size) +{ + SIZE_T new_capacity, max_capacity; + void *new_elements; + + if (element_count <= *capacity) + return TRUE; + + max_capacity = ~(SIZE_T)0 / element_size; + if (max_capacity < element_count) + return FALSE; + + new_capacity = max(*capacity, 4); + while (new_capacity < element_count && new_capacity <= max_capacity / 2) + new_capacity *= 2; + + if (new_capacity < element_count) + new_capacity = max_capacity; + + if (!(new_elements = heap_realloc(*elements, new_capacity * element_size))) + return FALSE; + + *elements = new_elements; + *capacity = new_capacity; + return TRUE; +} + +struct uia_node_array { + HUIANODE *nodes; + int node_count; + SIZE_T node_arr_size; +}; + +static void clear_node_array(struct uia_node_array *nodes) +{ + if (nodes->nodes) + { + int i; + + for (i = 0; i < nodes->node_count; i++) + UiaNodeRelease(nodes->nodes[i]); + + heap_free(nodes->nodes); + } + + memset(nodes, 0, sizeof(*nodes)); +} + +static HRESULT add_node_to_node_array(struct uia_node_array *out_nodes, HUIANODE node) +{ + if (!uia_array_reserve((void **)&out_nodes->nodes, &out_nodes->node_arr_size, out_nodes->node_count + 1, + sizeof(node))) + return E_OUTOFMEMORY; + + IWineUiaNode_AddRef((IWineUiaNode *)node); + out_nodes->nodes[out_nodes->node_count] = node; + out_nodes->node_count++; + + return S_OK; +} + static HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems) { LONG ubound; @@ -945,7 +1006,8 @@ exit: */ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *view_cond, struct UiaCondition *search_cond, struct UiaCondition *sibling_stop_cond, int traversal_opts, - BOOL at_root_level, BOOL exclude_root, BOOL *root_found, int max_depth, int *cur_depth, HUIANODE *out_node) + BOOL at_root_level, BOOL exclude_root, BOOL *root_found, int max_depth, int *cur_depth, + struct uia_node_array *out_nodes) { struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode); BOOL incr_depth = FALSE; @@ -972,8 +1034,10 @@ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *vi
if (uia_condition_matched(hr)) { - IWineUiaNode_AddRef((IWineUiaNode *)huianode); - *out_node = huianode; + hr = add_node_to_node_array(out_nodes, huianode); + if (FAILED(hr)) + goto exit; + hr = S_FALSE; goto exit; } @@ -994,7 +1058,7 @@ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *vi
if (SUCCEEDED(hr) && node2) hr = traverse_uia_node_tree(node2, view_cond, search_cond, sibling_stop_cond, traversal_opts, FALSE, - exclude_root, root_found, max_depth, cur_depth, out_node); + exclude_root, root_found, max_depth, cur_depth, out_nodes);
if (FAILED(hr) || hr == S_FALSE) goto exit; @@ -1019,7 +1083,7 @@ static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *vi
if (SUCCEEDED(hr) && node2) hr = traverse_uia_node_tree(node2, view_cond, search_cond, sibling_stop_cond, traversal_opts, at_root_level, - exclude_root, root_found, max_depth, cur_depth, out_node); + exclude_root, root_found, max_depth, cur_depth, out_nodes);
exit: UiaNodeRelease(huianode); @@ -2724,10 +2788,10 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode); SAFEARRAY *runtime_id, *req, *offsets, *tree_structs; struct UiaCondition *sibling_stop_cond; + struct uia_node_array nodes = { 0 }; BOOL root_found = FALSE; int cur_depth = 0; BSTR tree_struct; - HUIANODE node2; HRESULT hr; LONG idx;
@@ -2758,12 +2822,11 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str else sibling_stop_cond = (struct UiaCondition *)&UiaFalseCondition;
- node2 = NULL; IWineUiaNode_AddRef(&node->IWineUiaNode_iface); hr = traverse_uia_node_tree(huianode, cache_req->pViewCondition, find_params->pFindCondition, sibling_stop_cond, TreeTraversalOptions_Default, TRUE, find_params->ExcludeRoot, &root_found, find_params->MaxDepth, - &cur_depth, &node2); - if (FAILED(hr) || !node2) + &cur_depth, &nodes); + if (FAILED(hr) || !nodes.node_count) goto exit;
if (!(offsets = SafeArrayCreateVector(VT_I4, 0, 1))) @@ -2778,8 +2841,7 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str goto exit; }
- hr = UiaGetUpdatedCache(node2, cache_req, NormalizeState_None, NULL, &req, &tree_struct); - UiaNodeRelease(node2); + hr = UiaGetUpdatedCache(nodes.nodes[0], cache_req, NormalizeState_None, NULL, &req, &tree_struct); if (FAILED(hr)) goto exit;
@@ -2799,6 +2861,7 @@ HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, str
exit: VariantClear(&prop_cond.Value); + clear_node_array(&nodes);
if (FAILED(hr)) {