ReactOS 0.4.16-dev-2491-g3dc6630
uia_utils.c
Go to the documentation of this file.
1/*
2 * Copyright 2023 Connor McAdams for CodeWeavers
3 *
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.
8 *
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.
13 *
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
17 */
18
19#include "uia_private.h"
20
21#include "wine/debug.h"
22
24
25/*
26 * Global interface table helper functions.
27 */
29{
30 HRESULT hr;
31
33 CLSCTX_INPROC_SERVER, &IID_IGlobalInterfaceTable, (void **)git);
34 if (FAILED(hr))
35 WARN("Failed to get GlobalInterfaceTable, hr %#lx\n", hr);
36
37 return hr;
38}
39
41{
43 DWORD git_cookie;
44 HRESULT hr;
45
46 *ret_cookie = 0;
48 if (FAILED(hr))
49 return hr;
50
51 hr = IGlobalInterfaceTable_RegisterInterfaceInGlobal(git, iface, riid, &git_cookie);
52 if (FAILED(hr))
53 {
54 WARN("Failed to register interface in GlobalInterfaceTable, hr %#lx\n", hr);
55 return hr;
56 }
57
58 *ret_cookie = git_cookie;
59
60 return S_OK;
61}
62
64{
66 HRESULT hr;
67
69 if (FAILED(hr))
70 return hr;
71
72 hr = IGlobalInterfaceTable_RevokeInterfaceFromGlobal(git, git_cookie);
73 if (FAILED(hr))
74 WARN("Failed to revoke interface from GlobalInterfaceTable, hr %#lx\n", hr);
75
76 return hr;
77}
78
80{
82 IUnknown *iface;
83 HRESULT hr;
84
86 if (FAILED(hr))
87 return hr;
88
89 hr = IGlobalInterfaceTable_GetInterfaceFromGlobal(git, git_cookie, riid, (void **)&iface);
90 if (FAILED(hr))
91 {
92 ERR("Failed to get interface from Global Interface Table, hr %#lx\n", hr);
93 return hr;
94 }
95
96 *ret_iface = iface;
97
98 return S_OK;
99}
100
101#define UIA_RUNTIME_ID_PREFIX 42
103{
104 const int rt_id[2] = { UIA_RUNTIME_ID_PREFIX, HandleToUlong(hwnd) };
105 HRESULT hr;
106 LONG idx;
107
108 for (idx = 0; idx < ARRAY_SIZE(rt_id); idx++)
109 {
110 hr = SafeArrayPutElement(sa, &idx, (void *)&rt_id[idx]);
111 if (FAILED(hr))
112 return hr;
113 }
114
115 return S_OK;
116}
117
118/*
119 * UiaCondition cloning functions.
120 */
121static void uia_condition_destroy(struct UiaCondition *cond)
122{
123 if (!cond)
124 return;
125
126 switch (cond->ConditionType)
127 {
129 {
130 struct UiaPropertyCondition *prop_cond = (struct UiaPropertyCondition *)cond;
131
132 VariantClear(&prop_cond->Value);
133 break;
134 }
135
137 {
138 struct UiaNotCondition *not_cond = (struct UiaNotCondition *)cond;
139
141 break;
142 }
143
145 case ConditionType_Or:
146 {
147 struct UiaAndOrCondition *and_or_cond = (struct UiaAndOrCondition *)cond;
148 int i;
149
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;
154 }
155
156 default:
157 break;
158 }
159
160 free(cond);
161}
162
164{
165 HRESULT hr = S_OK;
166
167 *dst = NULL;
168 switch (src->ConditionType)
169 {
172 if (!(*dst = calloc(1, sizeof(**dst))))
173 return E_OUTOFMEMORY;
174
175 (*dst)->ConditionType = src->ConditionType;
176 break;
177
179 {
180 struct UiaPropertyCondition *prop_cond = calloc(1, sizeof(*prop_cond));
181 struct UiaPropertyCondition *src_cond = (struct UiaPropertyCondition *)src;
182
183 if (!prop_cond)
184 return E_OUTOFMEMORY;
185
186 *dst = (struct UiaCondition *)prop_cond;
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;
193 }
194
196 {
197 struct UiaNotCondition *not_cond = calloc(1, sizeof(*not_cond));
198 struct UiaNotCondition *src_cond = (struct UiaNotCondition *)src;
199
200 if (!not_cond)
201 return E_OUTOFMEMORY;
202
203 *dst = (struct UiaCondition *)not_cond;
205 hr = uia_condition_clone(&not_cond->pConditions, src_cond->pConditions);
206 break;
207 }
208
210 case ConditionType_Or:
211 {
212 struct UiaAndOrCondition *and_or_cond = calloc(1, sizeof(*and_or_cond));
213 struct UiaAndOrCondition *src_cond = (struct UiaAndOrCondition *)src;
214 int i;
215
216 if (!and_or_cond)
217 return E_OUTOFMEMORY;
218
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)
223 {
225 goto exit;
226 }
227
228 and_or_cond->cConditions = src_cond->cConditions;
229 for (i = 0; i < src_cond->cConditions; i++)
230 {
231 hr = uia_condition_clone(&and_or_cond->ppConditions[i], src_cond->ppConditions[i]);
232 if (FAILED(hr))
233 goto exit;
234 }
235
236 break;
237 }
238
239 default:
240 WARN("Tried to clone condition with invalid type %d\n", src->ConditionType);
241 return E_INVALIDARG;
242 }
243
244exit:
245 if (FAILED(hr))
246 {
248 *dst = NULL;
249 }
250
251 return hr;
252}
253
254/*
255 * UiaCacheRequest cloning functions.
256 */
258{
260 free(cache_req->pProperties);
261 free(cache_req->pPatterns);
262}
263
265{
266 HRESULT hr;
267
268 hr = uia_condition_clone(&dst->pViewCondition, src->pViewCondition);
269 if (FAILED(hr))
270 return hr;
271
272 dst->Scope = src->Scope;
273 dst->automationElementMode = src->automationElementMode;
274 if (src->cProperties)
275 {
276 if (!(dst->pProperties = calloc(src->cProperties, sizeof(*dst->pProperties))))
277 {
279 return E_OUTOFMEMORY;
280 }
281
282 dst->cProperties = src->cProperties;
283 memcpy(dst->pProperties, src->pProperties, sizeof(*dst->pProperties) * dst->cProperties);
284 }
285
286 if (src->cPatterns)
287 {
288 if (!(dst->pPatterns = calloc(src->cPatterns, sizeof(*dst->pPatterns))))
289 {
291 return E_OUTOFMEMORY;
292 }
293
294 dst->cPatterns = src->cPatterns;
295 memcpy(dst->pPatterns, src->pPatterns, sizeof(*dst->pPatterns) * dst->cPatterns);
296 }
297
298 return S_OK;
299}
300
302{
303 LONG ubound;
304 HRESULT hr;
305
306 *lbound = *elems = 0;
307 hr = SafeArrayGetLBound(sa, dim, lbound);
308 if (FAILED(hr))
309 return hr;
310
311 hr = SafeArrayGetUBound(sa, dim, &ubound);
312 if (FAILED(hr))
313 return hr;
314
315 *elems = (ubound - (*lbound)) + 1;
316 return S_OK;
317}
318
320{
321 UINT dims;
322
323 *lbound = *elems = 0;
324 dims = SafeArrayGetDim(sa);
325 if (dims != 1)
326 {
327 WARN("Invalid dimensions %d for safearray.\n", dims);
328 return E_FAIL;
329 }
330
331 return get_safearray_dim_bounds(sa, 1, lbound, elems);
332}
333
334int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
335{
336 LONG i, idx, lbound[2], elems[2];
337 int val[2];
338 HRESULT hr;
339
340 hr = get_safearray_bounds(sa1, &lbound[0], &elems[0]);
341 if (FAILED(hr))
342 {
343 ERR("Failed to get safearray bounds from sa1 with hr %#lx\n", hr);
344 return -1;
345 }
346
347 hr = get_safearray_bounds(sa2, &lbound[1], &elems[1]);
348 if (FAILED(hr))
349 {
350 ERR("Failed to get safearray bounds from sa2 with hr %#lx\n", hr);
351 return -1;
352 }
353
354 if (elems[0] != elems[1])
355 return (elems[0] > elems[1]) - (elems[0] < elems[1]);
356
357 if (prop_type != UIAutomationType_IntArray)
358 {
359 FIXME("Array type %#x value comparison currently unimplemented.\n", prop_type);
360 return -1;
361 }
362
363 for (i = 0; i < elems[0]; i++)
364 {
365 idx = lbound[0] + i;
366 hr = SafeArrayGetElement(sa1, &idx, &val[0]);
367 if (FAILED(hr))
368 {
369 ERR("Failed to get element from sa1 with hr %#lx\n", hr);
370 return -1;
371 }
372
373 idx = lbound[1] + i;
374 hr = SafeArrayGetElement(sa2, &idx, &val[1]);
375 if (FAILED(hr))
376 {
377 ERR("Failed to get element from sa2 with hr %#lx\n", hr);
378 return -1;
379 }
380
381 if (val[0] != val[1])
382 return (val[0] > val[1]) - (val[0] < val[1]);
383 }
384
385 return 0;
386}
387
388/*
389 * HWND related helper functions.
390 */
392{
393 RECT rect;
394
395 if (!IsWindowVisible(hwnd))
396 return FALSE;
397
398 if (!GetWindowRect(hwnd, &rect))
399 return FALSE;
400
401 if ((rect.right - rect.left) <= 0 || (rect.bottom - rect.top) <= 0)
402 return FALSE;
403
404 return TRUE;
405}
406
408{
410}
411
412/*
413 * rbtree to efficiently store a collection of HWNDs.
414 */
416{
419};
420
421static int uia_hwnd_map_hwnd_compare(const void *key, const struct rb_entry *entry)
422{
423 struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
424 HWND hwnd = (HWND)key;
425
426 return (hwnd_entry->hwnd > hwnd) - (hwnd_entry->hwnd < hwnd);
427}
428
429static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
430{
431 struct uia_hwnd_map_entry *hwnd_entry = RB_ENTRY_VALUE(entry, struct uia_hwnd_map_entry, entry);
432
433 TRACE("Removing hwnd %p from map %p\n", hwnd_entry->hwnd, context);
434 free(hwnd_entry);
435}
436
438{
439 return !!rb_get(hwnd_map, hwnd);
440}
441
443{
445
446 if (uia_hwnd_map_check_hwnd(hwnd_map, hwnd))
447 {
448 TRACE("hwnd %p already in map %p\n", hwnd, hwnd_map);
449 return S_OK;
450 }
451
452 if (!(entry = calloc(1, sizeof(*entry))))
453 return E_OUTOFMEMORY;
454
455 TRACE("Adding hwnd %p to map %p\n", hwnd, hwnd_map);
456 entry->hwnd = hwnd;
457 rb_put(hwnd_map, hwnd, &entry->entry);
458
459 return S_OK;
460}
461
463{
464 struct rb_entry *rb_entry = rb_get(hwnd_map, hwnd);
466
467 if (!rb_entry)
468 {
469 TRACE("hwnd %p not in map %p, nothing to remove.\n", hwnd, hwnd_map);
470 return;
471 }
472
473 TRACE("Removing hwnd %p from map %p\n", hwnd, hwnd_map);
475 rb_remove(hwnd_map, &entry->entry);
476 free(entry);
477}
478
479void uia_hwnd_map_init(struct rb_tree *hwnd_map)
480{
482}
483
484void uia_hwnd_map_destroy(struct rb_tree *hwnd_map)
485{
486 rb_destroy(hwnd_map, uia_hwnd_map_free, hwnd_map);
487}
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define HandleToUlong(h)
Definition: basetsd.h:73
const CLSID CLSID_StdGlobalInterfaceTable
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_FAIL
Definition: ddrawi.h:102
#define free
Definition: debug_ros.c:5
HRESULT hr
Definition: delayimp.cpp:573
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
unsigned int idx
Definition: utils.c:41
HRESULT WINAPI DECLSPEC_HOTPATCH CoCreateInstance(REFCLSID rclsid, IUnknown *outer, DWORD cls_context, REFIID riid, void **obj)
Definition: combase.c:1685
HANDLE HWND
Definition: compat.h:19
HRESULT WINAPI SafeArrayGetUBound(SAFEARRAY *psa, UINT nDim, LONG *plUbound)
Definition: safearray.c:1033
HRESULT WINAPI SafeArrayGetElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
Definition: safearray.c:947
UINT WINAPI SafeArrayGetDim(SAFEARRAY *psa)
Definition: safearray.c:1094
HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
Definition: safearray.c:1066
HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
Definition: safearray.c:864
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
GLenum src
Definition: glext.h:6340
GLenum GLenum dst
Definition: glext.h:6340
GLuint GLfloat * val
Definition: glext.h:7180
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
REFIID riid
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define FAILED(hr)
Definition: intsafe.h:51
uint32_t entry
Definition: isohybrid.c:63
#define memcpy(s1, s2, n)
Definition: mkisofs.h:878
unsigned int UINT
Definition: ndis.h:50
long LONG
Definition: pedump.c:60
#define REFIID
Definition: guiddef.h:118
#define calloc
Definition: rosglue.h:14
#define RB_ENTRY_VALUE(element, type, field)
Definition: rbtree.h:26
static void rb_destroy(struct rb_tree *tree, rb_traverse_func_t *callback, void *context)
Definition: rbtree.h:185
static int rb_put(struct rb_tree *tree, const void *key, struct rb_entry *entry)
Definition: rbtree.h:204
static struct rb_entry * rb_get(const struct rb_tree *tree, const void *key)
Definition: rbtree.h:192
static void rb_remove(struct rb_tree *tree, struct rb_entry *entry)
Definition: rbtree.h:272
static void rb_init(struct rb_tree *tree, rb_compare_func_t compare)
Definition: rbtree.h:173
#define exit(n)
Definition: config.h:202
#define TRACE(s)
Definition: solgame.cpp:4
& rect
Definition: startmenu.cpp:1413
enum ConditionType ConditionType
struct UiaCondition ** ppConditions
struct UiaCondition * pViewCondition
PROPERTYID * pProperties
enum ConditionType ConditionType
struct UiaCondition * pConditions
enum ConditionType ConditionType
enum ConditionType ConditionType
enum PropertyConditionFlags Flags
Definition: http.c:7252
Definition: copy.c:22
Definition: rbtree.h:30
Definition: rbtree.h:40
Definition: uia_utils.c:416
struct rb_entry entry
Definition: uia_utils.c:417
HWND hwnd
Definition: uia_utils.c:418
BOOL uia_hwnd_is_visible(HWND hwnd)
Definition: uia_utils.c:391
void uia_hwnd_map_init(struct rb_tree *hwnd_map)
Definition: uia_utils.c:479
HRESULT uia_cache_request_clone(struct UiaCacheRequest *dst, struct UiaCacheRequest *src)
Definition: uia_utils.c:264
#define UIA_RUNTIME_ID_PREFIX
Definition: uia_utils.c:101
HRESULT register_interface_in_git(IUnknown *iface, REFIID riid, DWORD *ret_cookie)
Definition: uia_utils.c:40
HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface)
Definition: uia_utils.c:79
BOOL uia_is_top_level_hwnd(HWND hwnd)
Definition: uia_utils.c:407
BOOL uia_hwnd_map_check_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
Definition: uia_utils.c:437
static int uia_hwnd_map_hwnd_compare(const void *key, const struct rb_entry *entry)
Definition: uia_utils.c:421
HRESULT uia_hwnd_map_add_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
Definition: uia_utils.c:442
HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems)
Definition: uia_utils.c:319
void uia_hwnd_map_destroy(struct rb_tree *hwnd_map)
Definition: uia_utils.c:484
HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd)
Definition: uia_utils.c:102
static HRESULT get_global_interface_table(IGlobalInterfaceTable **git)
Definition: uia_utils.c:28
void uia_hwnd_map_remove_hwnd(struct rb_tree *hwnd_map, HWND hwnd)
Definition: uia_utils.c:462
HRESULT unregister_interface_in_git(DWORD git_cookie)
Definition: uia_utils.c:63
HRESULT get_safearray_dim_bounds(SAFEARRAY *sa, UINT dim, LONG *lbound, LONG *elems)
Definition: uia_utils.c:301
static HRESULT uia_condition_clone(struct UiaCondition **dst, struct UiaCondition *src)
Definition: uia_utils.c:163
static void uia_hwnd_map_free(struct rb_entry *entry, void *context)
Definition: uia_utils.c:429
static void uia_condition_destroy(struct UiaCondition *cond)
Definition: uia_utils.c:121
void uia_cache_request_destroy(struct UiaCacheRequest *cache_req)
Definition: uia_utils.c:257
int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
Definition: uia_utils.c:334
@ ConditionType_Not
@ ConditionType_True
@ ConditionType_Or
@ ConditionType_Property
@ ConditionType_False
@ ConditionType_And
HRESULT WINAPI DECLSPEC_HOTPATCH VariantClear(VARIANTARG *pVarg)
Definition: variant.c:648
void WINAPI VariantInit(VARIANTARG *pVarg)
Definition: variant.c:568
HRESULT WINAPI VariantCopy(VARIANTARG *pvargDest, VARIANTARG *pvargSrc)
Definition: variant.c:748
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
BOOL WINAPI GetWindowRect(_In_ HWND, _Out_ LPRECT)
#define GA_PARENT
Definition: winuser.h:2892
HWND WINAPI GetDesktopWindow(void)
Definition: window.c:628
BOOL WINAPI IsWindowVisible(_In_ HWND)
HWND WINAPI GetAncestor(_In_ HWND, _In_ UINT)
Definition: window.c:929