d3d10/effect: Add support for 'imul' instruction.
[wine.git] / dlls / uiautomationcore / uia_utils.c
blob866358f97c83e0d0b4c225b878528f614b350474
1 /*
2 * Copyright 2023 Connor McAdams for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "uia_private.h"
21 #include "wine/debug.h"
23 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
26 * Global interface table helper functions.
28 static HRESULT get_global_interface_table(IGlobalInterfaceTable **git)
30 HRESULT hr;
32 hr = CoCreateInstance(&CLSID_StdGlobalInterfaceTable, NULL,
33 CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)git);
34 if (FAILED(hr))
35 WARN("Failed to get GlobalInterfaceTable, hr %#lx\n", hr);
37 return hr;
40 HRESULT register_interface_in_git(IUnknown *iface, REFIID riid, DWORD *ret_cookie)
42 IGlobalInterfaceTable *git;
43 DWORD git_cookie;
44 HRESULT hr;
46 *ret_cookie = 0;
47 hr = get_global_interface_table(&git);
48 if (FAILED(hr))
49 return hr;
51 hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, iface, riid, &git_cookie);
52 if (FAILED(hr))
54 WARN("Failed to register interface in GlobalInterfaceTable, hr %#lx\n", hr);
55 return hr;
58 *ret_cookie = git_cookie;
60 return S_OK;
63 HRESULT unregister_interface_in_git(DWORD git_cookie)
65 IGlobalInterfaceTable *git;
66 HRESULT hr;
68 hr = get_global_interface_table(&git);
69 if (FAILED(hr))
70 return hr;
72 hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, git_cookie);
73 if (FAILED(hr))
74 WARN("Failed to revoke interface from GlobalInterfaceTable, hr %#lx\n", hr);
76 return hr;
79 HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface)
81 IGlobalInterfaceTable *git;
82 IUnknown *iface;
83 HRESULT hr;
85 hr = get_global_interface_table(&git);
86 if (FAILED(hr))
87 return hr;
89 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, git_cookie, riid, (void **)&iface);
90 if (FAILED(hr))
92 ERR("Failed to get interface from Global Interface Table, hr %#lx\n", hr);
93 return hr;
96 *ret_iface = iface;
98 return S_OK;
101 #define UIA_RUNTIME_ID_PREFIX 42
102 HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd)
104 const int rt_id[2] = { UIA_RUNTIME_ID_PREFIX, HandleToUlong(hwnd) };
105 HRESULT hr;
106 LONG idx;
108 for (idx = 0; idx < ARRAY_SIZE(rt_id); idx++)
110 hr = SafeArrayPutElement(sa, &idx, (void *)&rt_id[idx]);
111 if (FAILED(hr))
112 return hr;
115 return S_OK;
119 * UiaCondition cloning functions.
121 static void uia_condition_destroy(struct UiaCondition *cond)
123 if (!cond)
124 return;
126 switch (cond->ConditionType)
128 case ConditionType_Property:
130 struct UiaPropertyCondition *prop_cond = (struct UiaPropertyCondition *)cond;
132 VariantClear(&prop_cond->Value);
133 break;
136 case ConditionType_Not:
138 struct UiaNotCondition *not_cond = (struct UiaNotCondition *)cond;
140 uia_condition_destroy(not_cond->pConditions);
141 break;
144 case ConditionType_And:
145 case ConditionType_Or:
147 struct UiaAndOrCondition *and_or_cond = (struct UiaAndOrCondition *)cond;
148 int i;
150 for (i = 0; i < and_or_cond->cConditions; i++)
151 uia_condition_destroy(and_or_cond->ppConditions[i]);
152 free(and_or_cond->ppConditions);
153 break;
156 default:
157 break;
160 free(cond);
163 static HRESULT uia_condition_clone(struct UiaCondition **dst, struct UiaCondition *src)
165 HRESULT hr = S_OK;
167 *dst = NULL;
168 switch (src->ConditionType)
170 case ConditionType_True:
171 case ConditionType_False:
172 if (!(*dst = calloc(1, sizeof(**dst))))
173 return E_OUTOFMEMORY;
175 (*dst)->ConditionType = src->ConditionType;
176 break;
178 case ConditionType_Property:
180 struct UiaPropertyCondition *prop_cond = calloc(1, sizeof(*prop_cond));
181 struct UiaPropertyCondition *src_cond = (struct UiaPropertyCondition *)src;
183 if (!prop_cond)
184 return E_OUTOFMEMORY;
186 *dst = (struct UiaCondition *)prop_cond;
187 prop_cond->ConditionType = ConditionType_Property;
188 prop_cond->PropertyId = src_cond->PropertyId;
189 prop_cond->Flags = src_cond->Flags;
190 VariantInit(&prop_cond->Value);
191 hr = VariantCopy(&prop_cond->Value, &src_cond->Value);
192 break;
195 case ConditionType_Not:
197 struct UiaNotCondition *not_cond = calloc(1, sizeof(*not_cond));
198 struct UiaNotCondition *src_cond = (struct UiaNotCondition *)src;
200 if (!not_cond)
201 return E_OUTOFMEMORY;
203 *dst = (struct UiaCondition *)not_cond;
204 not_cond->ConditionType = ConditionType_Not;
205 hr = uia_condition_clone(&not_cond->pConditions, src_cond->pConditions);
206 break;
209 case ConditionType_And:
210 case ConditionType_Or:
212 struct UiaAndOrCondition *and_or_cond = calloc(1, sizeof(*and_or_cond));
213 struct UiaAndOrCondition *src_cond = (struct UiaAndOrCondition *)src;
214 int i;
216 if (!and_or_cond)
217 return E_OUTOFMEMORY;
219 *dst = (struct UiaCondition *)and_or_cond;
220 and_or_cond->ConditionType = src_cond->ConditionType;
221 and_or_cond->ppConditions = calloc(src_cond->cConditions, sizeof(*and_or_cond->ppConditions));
222 if (!and_or_cond->ppConditions)
224 hr = E_OUTOFMEMORY;
225 goto exit;
228 and_or_cond->cConditions = src_cond->cConditions;
229 for (i = 0; i < src_cond->cConditions; i++)
231 hr = uia_condition_clone(&and_or_cond->ppConditions[i], src_cond->ppConditions[i]);
232 if (FAILED(hr))
233 goto exit;
236 break;
239 default:
240 WARN("Tried to clone condition with invalid type %d\n", src->ConditionType);
241 return E_INVALIDARG;
244 exit:
245 if (FAILED(hr))
247 uia_condition_destroy(*dst);
248 *dst = NULL;
251 return hr;
255 * UiaCacheRequest cloning functions.
257 void uia_cache_request_destroy(struct UiaCacheRequest *cache_req)
259 uia_condition_destroy(cache_req->pViewCondition);
260 free(cache_req->pProperties);
261 free(cache_req->pPatterns);
264 HRESULT uia_cache_request_clone(struct UiaCacheRequest *dst, struct UiaCacheRequest *src)
266 HRESULT hr;
268 hr = uia_condition_clone(&dst->pViewCondition, src->pViewCondition);
269 if (FAILED(hr))
270 return hr;
272 dst->Scope = src->Scope;
273 dst->automationElementMode = src->automationElementMode;
274 if (src->cProperties)
276 if (!(dst->pProperties = calloc(src->cProperties, sizeof(*dst->pProperties))))
278 uia_cache_request_destroy(dst);
279 return E_OUTOFMEMORY;
282 dst->cProperties = src->cProperties;
283 memcpy(dst->pProperties, src->pProperties, sizeof(*dst->pProperties) * dst->cProperties);
286 if (src->cPatterns)
288 if (!(dst->pPatterns = calloc(src->cPatterns, sizeof(*dst->pPatterns))))
290 uia_cache_request_destroy(dst);
291 return E_OUTOFMEMORY;
294 dst->cPatterns = src->cPatterns;
295 memcpy(dst->pPatterns, src->pPatterns, sizeof(*dst->pPatterns) * dst->cPatterns);
298 return S_OK;
301 HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *elems)
303 LONG ubound;
304 HRESULT hr;
306 *lbound = *elems = 0;
307 hr = SafeArrayGetLBound(sa, dim, lbound);
308 if (FAILED(hr))
309 return hr;
311 hr = SafeArrayGetUBound(sa, dim, &ubound);
312 if (FAILED(hr))
313 return hr;
315 *elems = (ubound - (*lbound)) + 1;
316 return S_OK;
319 HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems)
321 UINT dims;
323 *lbound = *elems = 0;
324 dims = SafeArrayGetDim(sa);
325 if (dims != 1)
327 WARN("Invalid dimensions %d for safearray.\n", dims);
328 return E_FAIL;
331 return get_safearray_dim_bounds(sa, 1, lbound, elems);
334 int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
336 LONG i, idx, lbound[2], elems[2];
337 int val[2];
338 HRESULT hr;
340 hr = get_safearray_bounds(sa1, &lbound[0], &elems[0]);
341 if (FAILED(hr))
343 ERR("Failed to get safearray bounds from sa1 with hr %#lx\n", hr);
344 return -1;
347 hr = get_safearray_bounds(sa2, &lbound[1], &elems[1]);
348 if (FAILED(hr))
350 ERR("Failed to get safearray bounds from sa2 with hr %#lx\n", hr);
351 return -1;
354 if (elems[0] != elems[1])
355 return (elems[0] > elems[1]) - (elems[0] < elems[1]);
357 if (prop_type != UIAutomationType_IntArray)
359 FIXME("Array type %#x value comparison currently unimplemented.\n", prop_type);
360 return -1;
363 for (i = 0; i < elems[0]; i++)
365 idx = lbound[0] + i;
366 hr = SafeArrayGetElement(sa1, &idx, &val[0]);
367 if (FAILED(hr))
369 ERR("Failed to get element from sa1 with hr %#lx\n", hr);
370 return -1;
373 idx = lbound[1] + i;
374 hr = SafeArrayGetElement(sa2, &idx, &val[1]);
375 if (FAILED(hr))
377 ERR("Failed to get element from sa2 with hr %#lx\n", hr);
378 return -1;
381 if (val[0] != val[1])
382 return (val[0] > val[1]) - (val[0] < val[1]);
385 return 0;
389 * HWND related helper functions.
391 BOOL uia_hwnd_is_visible(HWND hwnd)
393 RECT rect;
395 if (!IsWindowVisible(hwnd))
396 return FALSE;
398 if (!GetWindowRect(hwnd, &rect))
399 return FALSE;
401 if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0)
402 return FALSE;
404 return TRUE;
407 BOOL uia_is_top_level_hwnd(HWND hwnd)
409 return GetAncestor(hwnd, GA_PARENT) == GetDesktopWindow();
413 * rbtree to efficiently store a collection of HWNDs.
415 struct uia_hwnd_map_entry
417 struct rb_entry entry;
418 HWND hwnd;
421 static int uia_hwnd_map_hwnd_compare(const void *key, const struct rb_entry *entry)
423 struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
424 HWND hwnd = (HWND)key;
426 return (hwnd_entry->hwnd > hwnd) - (hwnd_entry->hwnd < hwnd);
429 static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
431 struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
433 TRACE("Removing hwnd %p from map %p\n", hwnd_entry->hwnd, context);
434 free(hwnd_entry);
437 BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
439 return !!rb_get(hwnd_map, hwnd);
442 HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
444 struct uia_hwnd_map_entry *entry;
446 if (uia_hwnd_map_check_hwnd(hwnd_map, hwnd))
448 TRACE("hwnd %p already in map %p\n", hwnd, hwnd_map);
449 return S_OK;
452 if (!(entry = calloc(1, sizeof(*entry))))
453 return E_OUTOFMEMORY;
455 TRACE("Adding hwnd %p to map %p\n", hwnd, hwnd_map);
456 entry->hwnd = hwnd;
457 rb_put(hwnd_map, hwnd, &entry->entry);
459 return S_OK;
462 void uia_hwnd_map_init(struct rb_tree *hwnd_map)
464 rb_init(hwnd_map, uia_hwnd_map_hwnd_compare);
467 void uia_hwnd_map_destroy(struct rb_tree *hwnd_map)
469 rb_destroy(hwnd_map, uia_hwnd_map_free, hwnd_map);