ReactOS 0.4.16-dev-2491-g3dc6630
uia_client.c
Go to the documentation of this file.
1/*
2 * Copyright 2022 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
26
28 HUIANODE *nodes;
31};
32
33static void clear_node_array(struct uia_node_array *nodes)
34{
35 if (nodes->nodes)
36 {
37 int i;
38
39 for (i = 0; i < nodes->node_count; i++)
40 UiaNodeRelease(nodes->nodes[i]);
41
42 free(nodes->nodes);
43 }
44
45 memset(nodes, 0, sizeof(*nodes));
46}
47
48static HRESULT add_node_to_node_array(struct uia_node_array *out_nodes, HUIANODE node)
49{
50 if (!uia_array_reserve((void **)&out_nodes->nodes, &out_nodes->node_arr_size, out_nodes->node_count + 1,
51 sizeof(node)))
52 return E_OUTOFMEMORY;
53
54 IWineUiaNode_AddRef((IWineUiaNode *)node);
55 out_nodes->nodes[out_nodes->node_count] = node;
56 out_nodes->node_count++;
57
58 return S_OK;
59}
60
62{
63 HUIANODE node;
64 HRESULT hr;
65 LONG i;
66
67 for (i = 0; i < elems; i++)
68 {
70 if (FAILED(hr))
71 break;
73 }
74}
75
77{
78 LONG i, idx, lbound, elems;
79 HUIANODE node;
81 HRESULT hr;
82
83 if (FAILED(get_safearray_bounds(V_ARRAY(in), &lbound, &elems)))
84 return;
85
86 if (!(sa = SafeArrayCreateVector(VT_UINT_PTR, 0, elems)))
87 return;
88
89 for (i = 0; i < elems; i++)
90 {
91 IRawElementProviderSimple *elprov;
92 IUnknown *unk;
93
94 idx = lbound + i;
96 if (FAILED(hr))
97 break;
98
99 hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov);
100 IUnknown_Release(unk);
101 if (FAILED(hr))
102 break;
103
104 hr = UiaNodeFromProvider(elprov, &node);
105 if (FAILED(hr))
106 break;
107
108 IRawElementProviderSimple_Release(elprov);
110 if (FAILED(hr))
111 break;
112 }
113
114 if (FAILED(hr))
115 {
118 return;
119 }
120
122 V_ARRAY(out) = sa;
123}
124
125/* Convert a VT_UINT_PTR SAFEARRAY to VT_UNKNOWN. */
127{
128 SAFEARRAY *sa = NULL;
129 LONG ubound, i;
130 HUIANODE node;
131 HRESULT hr;
132
133 hr = SafeArrayGetUBound(V_ARRAY(in), 1, &ubound);
134 if (FAILED(hr))
135 goto exit;
136
137 if (!(sa = SafeArrayCreateVector(VT_UNKNOWN, 0, ubound + 1)))
138 {
139 hr = E_FAIL;
140 goto exit;
141 }
142
143 for (i = 0; i < (ubound + 1); i++)
144 {
146 if (FAILED(hr))
147 break;
148
150 if (FAILED(hr))
151 break;
152
154 }
155
156exit:
157 if (FAILED(hr))
158 {
160 if (sa)
162 }
163
165 if (SUCCEEDED(hr))
166 {
168 V_ARRAY(in) = sa;
169 }
170}
171
172static HWND get_hwnd_from_provider(IRawElementProviderSimple *elprov)
173{
174 IRawElementProviderSimple *host_prov;
175 HRESULT hr;
176 VARIANT v;
177 HWND hwnd;
178
179 hwnd = NULL;
180 VariantInit(&v);
181 hr = IRawElementProviderSimple_get_HostRawElementProvider(elprov, &host_prov);
182 if (SUCCEEDED(hr) && host_prov)
183 {
184 hr = IRawElementProviderSimple_GetPropertyValue(host_prov, UIA_NativeWindowHandlePropertyId, &v);
185 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
187
188 VariantClear(&v);
189 IRawElementProviderSimple_Release(host_prov);
190 }
191
192 if (!IsWindow(hwnd))
193 {
194 hr = IRawElementProviderSimple_GetPropertyValue(elprov, UIA_NativeWindowHandlePropertyId, &v);
195 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
197 VariantClear(&v);
198 }
199
200 return hwnd;
201}
202
203static IRawElementProviderSimple *get_provider_hwnd_fragment_root(IRawElementProviderSimple *elprov, HWND *hwnd)
204{
205 IRawElementProviderFragmentRoot *elroot, *elroot2;
206 IRawElementProviderSimple *elprov2, *ret;
207 IRawElementProviderFragment *elfrag;
208 HRESULT hr;
209 int depth;
210
211 *hwnd = NULL;
212
213 hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
214 if (FAILED(hr) || !elfrag)
215 return NULL;
216
217 depth = 0;
218 ret = NULL;
219 elroot = elroot2 = NULL;
220
221 /*
222 * Recursively walk up the fragment root chain until:
223 * We get a fragment root that has an HWND associated with it.
224 * We get a NULL fragment root.
225 * We get the same fragment root as the current fragment root.
226 * We've gone up the chain ten times.
227 */
228 while (depth < 10)
229 {
230 hr = IRawElementProviderFragment_get_FragmentRoot(elfrag, &elroot);
231 IRawElementProviderFragment_Release(elfrag);
232 if (FAILED(hr) || !elroot || (elroot == elroot2))
233 break;
234
235 hr = IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderSimple, (void **)&elprov2);
236 if (FAILED(hr) || !elprov2)
237 break;
238
239 *hwnd = get_hwnd_from_provider(elprov2);
240 if (IsWindow(*hwnd))
241 {
242 ret = elprov2;
243 break;
244 }
245
246 hr = IRawElementProviderSimple_QueryInterface(elprov2, &IID_IRawElementProviderFragment, (void **)&elfrag);
247 IRawElementProviderSimple_Release(elprov2);
248 if (FAILED(hr) || !elfrag)
249 break;
250
251 if (elroot2)
252 IRawElementProviderFragmentRoot_Release(elroot2);
253 elroot2 = elroot;
254 elroot = NULL;
255 depth++;
256 }
257
258 if (elroot)
259 IRawElementProviderFragmentRoot_Release(elroot);
260 if (elroot2)
261 IRawElementProviderFragmentRoot_Release(elroot2);
262
263 return ret;
264}
265
267{
268 int i, prov_idx;
269
270 for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++)
271 {
272 if (node->prov[i])
273 {
274 if (prov_idx == idx)
275 return i;
276 else
277 prov_idx++;
278 }
279 }
280
281 ERR("Node %p has no provider at idx %d\n", node, idx);
282 return 0;
283}
284
285static HRESULT get_prop_val_from_node_provider(IWineUiaNode *node, const struct uia_prop_info *prop_info, int idx,
286 VARIANT *out_val)
287{
288 IWineUiaProvider *prov;
289 HRESULT hr;
290
291 VariantInit(out_val);
292 hr = IWineUiaNode_get_provider(node, idx, &prov);
293 if (FAILED(hr))
294 return hr;
295
296 hr = IWineUiaProvider_get_prop_val(prov, prop_info, out_val);
297 IWineUiaProvider_Release(prov);
298
299 return hr;
300}
301
302static HRESULT get_prov_opts_from_node_provider(IWineUiaNode *node, int idx, int *out_opts)
303{
304 IWineUiaProvider *prov;
305 HRESULT hr;
306
307 *out_opts = 0;
308 hr = IWineUiaNode_get_provider(node, idx, &prov);
309 if (FAILED(hr))
310 return hr;
311
312 hr = IWineUiaProvider_get_prov_opts(prov, out_opts);
313 IWineUiaProvider_Release(prov);
314
315 return hr;
316}
317
318static HRESULT get_has_parent_from_node_provider(IWineUiaNode *node, int idx, BOOL *out_val)
319{
320 IWineUiaProvider *prov;
321 HRESULT hr;
322
323 *out_val = FALSE;
324 hr = IWineUiaNode_get_provider(node, idx, &prov);
325 if (FAILED(hr))
326 return hr;
327
328 hr = IWineUiaProvider_has_parent(prov, out_val);
329 IWineUiaProvider_Release(prov);
330
331 return hr;
332}
333
334static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int nav_dir, VARIANT *ret_val)
335{
336 IWineUiaProvider *prov;
337 HRESULT hr;
338
339 VariantInit(ret_val);
340 hr = IWineUiaNode_get_provider(node, idx, &prov);
341 if (FAILED(hr))
342 return hr;
343
344 hr = IWineUiaProvider_navigate(prov, nav_dir, ret_val);
345 IWineUiaProvider_Release(prov);
346
347 return hr;
348}
349
351{
352 IWineUiaProvider *prov;
353 HRESULT hr;
354
355 VariantInit(ret_val);
356 hr = IWineUiaNode_get_provider(node, idx, &prov);
357 if (FAILED(hr))
358 return hr;
359
360 hr = IWineUiaProvider_get_focus(prov, flags, ret_val);
361 IWineUiaProvider_Release(prov);
362
363 return hr;
364}
365
366static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEVENT huiaevent)
367{
368 IWineUiaProvider *prov;
369 HRESULT hr;
370
371 hr = IWineUiaNode_get_provider(node, idx, &prov);
372 if (FAILED(hr))
373 return hr;
374
375 hr = IWineUiaProvider_attach_event(prov, (LONG_PTR)huiaevent);
376 IWineUiaProvider_Release(prov);
377
378 return hr;
379}
380
382 LONG child_id, IProxyProviderWinEventSink *sink)
383{
384 IWineUiaProvider *prov;
385 HRESULT hr;
386
387 hr = IWineUiaNode_get_provider(node, idx, &prov);
388 if (FAILED(hr))
389 return hr;
390
391 hr = IWineUiaProvider_respond_to_win_event(prov, win_event, HandleToUlong(hwnd), obj_id, child_id, sink);
392 IWineUiaProvider_Release(prov);
393
394 return hr;
395}
396
398{
399 IWineUiaProvider *prov;
400 HRESULT hr;
401
402 VariantInit(ret_val);
403 hr = IWineUiaNode_get_provider(node, idx, &prov);
404 if (FAILED(hr))
405 return hr;
406
407 hr = IWineUiaProvider_create_node_from_prov(prov, flags, ret_val);
408 IWineUiaProvider_Release(prov);
409
410 return hr;
411}
412
413/*
414 * IWineUiaNode interface.
415 */
416static HRESULT WINAPI uia_node_QueryInterface(IWineUiaNode *iface, REFIID riid, void **ppv)
417{
418 *ppv = NULL;
419 if (IsEqualIID(riid, &IID_IWineUiaNode) || IsEqualIID(riid, &IID_IUnknown))
420 *ppv = iface;
421 else
422 return E_NOINTERFACE;
423
424 IWineUiaNode_AddRef(iface);
425 return S_OK;
426}
427
428static ULONG WINAPI uia_node_AddRef(IWineUiaNode *iface)
429{
430 struct uia_node *node = impl_from_IWineUiaNode(iface);
432
433 TRACE("%p, refcount %ld\n", node, ref);
434 return ref;
435}
436
437static ULONG WINAPI uia_node_Release(IWineUiaNode *iface)
438{
439 struct uia_node *node = impl_from_IWineUiaNode(iface);
441
442 TRACE("%p, refcount %ld\n", node, ref);
443 if (!ref)
444 {
445 int i;
446
447 for (i = 0; i < PROV_TYPE_COUNT; i++)
448 {
449 if (node->git_cookie[i])
450 {
451 if (FAILED(unregister_interface_in_git(node->git_cookie[i])))
452 WARN("Failed to get revoke provider interface from GIT\n");
453 }
454
455 if (node->prov[i])
456 IWineUiaProvider_Release(node->prov[i]);
457 }
458
459 if (!list_empty(&node->prov_thread_list_entry))
460 uia_provider_thread_remove_node((HUIANODE)iface);
461 if (node->nested_node)
463
464 free(node);
465 }
466
467 return ref;
468}
469
470static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, int idx, IWineUiaProvider **out_prov)
471{
472 struct uia_node *node = impl_from_IWineUiaNode(iface);
473 int prov_type;
474
475 TRACE("(%p, %d, %p)\n", iface, idx, out_prov);
476
477 *out_prov = NULL;
478 if (node->disconnected)
480
481 if (idx >= node->prov_count)
482 return E_INVALIDARG;
483
485 if (node->git_cookie[prov_type])
486 {
487 IWineUiaProvider *prov;
488 HRESULT hr;
489
490 hr = get_interface_in_git(&IID_IWineUiaProvider, node->git_cookie[prov_type], (IUnknown **)&prov);
491 if (FAILED(hr))
492 return hr;
493
494 *out_prov = prov;
495 }
496 else
497 {
498 *out_prov = node->prov[prov_type];
499 IWineUiaProvider_AddRef(node->prov[prov_type]);
500 }
501
502 return S_OK;
503}
504
505static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *prop_guid,
506 VARIANT *ret_val)
507{
508 int prop_id = UiaLookupId(AutomationIdentifierType_Property, prop_guid);
509 struct uia_node *node = impl_from_IWineUiaNode(iface);
510 HRESULT hr;
511 VARIANT v;
512
513 TRACE("%p, %s, %p\n", iface, debugstr_guid(prop_guid), ret_val);
514
515 if (node->disconnected)
516 {
517 VariantInit(ret_val);
519 }
520
521 hr = UiaGetPropertyValue((HUIANODE)iface, prop_id, &v);
522
523 /* VT_UNKNOWN is UiaGetReservedNotSupported value, no need to marshal it. */
524 if (V_VT(&v) == VT_UNKNOWN)
525 V_VT(ret_val) = VT_EMPTY;
526 else
527 *ret_val = v;
528
529 return hr;
530}
531
532static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface)
533{
534 struct uia_node *node = impl_from_IWineUiaNode(iface);
535 int prov_type;
536
537 TRACE("%p\n", node);
538
539 if (node->disconnected)
540 {
541 ERR("Attempted to disconnect node which was already disconnected.\n");
542 return E_FAIL;
543 }
544
545 /* Nested nodes can only have one provider. */
546 prov_type = get_node_provider_type_at_idx(node, 0);
547 if (node->git_cookie[prov_type])
548 {
549 if (FAILED(unregister_interface_in_git(node->git_cookie[prov_type])))
550 WARN("Failed to get revoke provider interface from GIT\n");
551 node->git_cookie[prov_type] = 0;
552 }
553
554 IWineUiaProvider_Release(node->prov[prov_type]);
555 node->prov[prov_type] = NULL;
556
557 node->disconnected = TRUE;
558 node->prov_count = 0;
559
560 return S_OK;
561}
562
563static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd)
564{
565 struct uia_node *node = impl_from_IWineUiaNode(iface);
566
567 TRACE("%p, %p\n", node, out_hwnd);
568
569 *out_hwnd = HandleToUlong(node->hwnd);
570
571 return S_OK;
572}
573
574static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, LONG proc_id, LONG event_cookie,
575 IWineUiaEvent **ret_event)
576{
577 struct uia_node *node = impl_from_IWineUiaNode(iface);
578 struct uia_event *event = NULL;
579 int old_event_advisers_count;
580 HRESULT hr;
581
582 TRACE("%p, %ld, %ld, %p\n", node, proc_id, event_cookie, ret_event);
583
584 *ret_event = NULL;
586 if (FAILED(hr))
587 return hr;
588
589 /* Newly created serverside event. */
590 if (hr == S_OK)
591 *ret_event = &event->IWineUiaEvent_iface;
592
593 old_event_advisers_count = event->event_advisers_count;
594 hr = attach_event_to_node_provider(iface, 0, (HUIAEVENT)event);
595 if (FAILED(hr))
596 {
597 IWineUiaEvent_Release(&event->IWineUiaEvent_iface);
598 *ret_event = NULL;
599 return hr;
600 }
601
602 /*
603 * Pre-existing serverside event that has already had its initial
604 * advise call and gotten event data - if we've got new advisers, we need
605 * to advise them here.
606 */
607 if (!(*ret_event) && event->event_id && (event->event_advisers_count != old_event_advisers_count))
608 hr = IWineUiaEvent_advise_events(&event->IWineUiaEvent_iface, TRUE, old_event_advisers_count);
609
610 return hr;
611}
612
613static const IWineUiaNodeVtbl uia_node_vtbl = {
622};
623
624static struct uia_node *unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface)
625{
626 if (!iface || (iface->lpVtbl != &uia_node_vtbl))
627 return NULL;
628
629 return CONTAINING_RECORD(iface, struct uia_node, IWineUiaNode_iface);
630}
631
632static HRESULT create_uia_node(struct uia_node **out_node, int node_flags)
633{
634 struct uia_node *node;
635
636 *out_node = NULL;
637 if (!(node = calloc(1, sizeof(*node))))
638 return E_OUTOFMEMORY;
639
640 node->IWineUiaNode_iface.lpVtbl = &uia_node_vtbl;
641 list_init(&node->prov_thread_list_entry);
642 list_init(&node->node_map_list_entry);
643 node->ref = 1;
645 node->ignore_clientside_hwnd_provs = TRUE;
646 if (node_flags & NODE_FLAG_NO_PREPARE)
647 node->no_prepare = TRUE;
648 if (node_flags & NODE_FLAG_IGNORE_COM_THREADING)
649 node->ignore_com_threading = TRUE;
650
651 *out_node = node;
652 return S_OK;
653}
654
655static BOOL is_nested_node_provider(IWineUiaProvider *iface);
657{
658 int i, prov_idx;
659 HRESULT hr;
660
661 if (node->no_prepare)
662 return S_OK;
663
664 /* Get the provider index for the provider that created the node. */
665 for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++)
666 {
667 if (i == node->creator_prov_type)
668 {
669 node->creator_prov_idx = prov_idx;
670 break;
671 }
672 else if (node->prov[i])
673 prov_idx++;
674 }
675
676 /*
677 * HUIANODEs can only have one 'parent link' provider, which handles
678 * parent and sibling navigation for the entire HUIANODE. Each provider is
679 * queried for a parent in descending order, starting with the override
680 * provider. The first provider to have a valid parent is made parent
681 * link. If no providers return a valid parent, the provider at index 0
682 * is made parent link by default.
683 */
684 for (i = prov_idx = 0; i < PROV_TYPE_COUNT; i++)
685 {
686 BOOL has_parent;
687
688 if (!node->prov[i])
689 continue;
690
691 hr = get_has_parent_from_node_provider(&node->IWineUiaNode_iface, prov_idx, &has_parent);
692 if (SUCCEEDED(hr) && has_parent)
693 {
694 node->parent_link_idx = prov_idx;
695 break;
696 }
697
698 prov_idx++;
699 }
700
701 if (node->ignore_com_threading)
702 return S_OK;
703
704 for (i = 0; i < PROV_TYPE_COUNT; i++)
705 {
706 enum ProviderOptions prov_opts;
707 struct uia_provider *prov;
708 HRESULT hr;
709
710 /* Only regular providers need to be queried for UseComThreading. */
711 if (!node->prov[i] || is_nested_node_provider(node->prov[i]))
712 continue;
713
714 prov = impl_from_IWineUiaProvider(node->prov[i]);
715 hr = IRawElementProviderSimple_get_ProviderOptions(prov->elprov, &prov_opts);
716 if (FAILED(hr))
717 continue;
718
719 /*
720 * If the UseComThreading ProviderOption is specified, all calls to the
721 * provided IRawElementProviderSimple need to respect the apartment type
722 * of the thread that creates the HUIANODE. i.e, if it's created in an
723 * STA, and the HUIANODE is used in an MTA, we need to provide a proxy.
724 */
725 if (prov_opts & ProviderOptions_UseComThreading)
726 {
727 hr = register_interface_in_git((IUnknown *)&prov->IWineUiaProvider_iface, &IID_IWineUiaProvider,
728 &node->git_cookie[i]);
729 if (FAILED(hr))
730 return hr;
731 }
732 }
733
734 return S_OK;
735}
736
737static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, int prov_type);
738HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node)
739{
740 struct uia_node *in_node_data = impl_from_IWineUiaNode((IWineUiaNode *)in_node);
741 struct uia_node *node;
742 HRESULT hr = S_OK;
743 int i;
744
745 *out_node = NULL;
746 if (in_node_data->nested_node)
747 {
748 FIXME("Cloning of nested nodes currently unimplemented\n");
749 return E_NOTIMPL;
750 }
751
752 for (i = 0; i < PROV_TYPE_COUNT; i++)
753 {
754 if (in_node_data->prov[i] && is_nested_node_provider(in_node_data->prov[i]))
755 {
756 FIXME("Cloning of nested node providers currently unimplemented\n");
757 return E_NOTIMPL;
758 }
759 }
760
761 hr = create_uia_node(&node, 0);
762 if (FAILED(hr))
763 return hr;
764
765 node->hwnd = in_node_data->hwnd;
766 for (i = 0; i < PROV_TYPE_COUNT; i++)
767 {
768 struct uia_provider *in_prov_data;
769
770 if (!in_node_data->prov[i])
771 continue;
772
773 in_prov_data = impl_from_IWineUiaProvider(in_node_data->prov[i]);
774 hr = create_wine_uia_provider(node, in_prov_data->elprov, i);
775 if (FAILED(hr))
776 goto exit;
777
778 if (in_node_data->git_cookie[i])
779 {
780 hr = register_interface_in_git((IUnknown *)node->prov[i], &IID_IWineUiaProvider, &node->git_cookie[i]);
781 if (FAILED(hr))
782 goto exit;
783 }
784 }
785
786 node->parent_link_idx = in_node_data->parent_link_idx;
787 node->creator_prov_idx = in_node_data->creator_prov_idx;
788 node->creator_prov_type = in_node_data->creator_prov_type;
789
790 *out_node = (void *)&node->IWineUiaNode_iface;
791 TRACE("Created clone node %p from node %p\n", *out_node, in_node);
792
793exit:
794 if (FAILED(hr))
795 IWineUiaNode_Release(&node->IWineUiaNode_iface);
796
797 return hr;
798}
799
801{
802 if (node->creator_prov_idx == node->parent_link_idx)
803 return TRUE;
804 else
805 return FALSE;
806}
807
808static HRESULT get_sibling_from_node_provider(struct uia_node *node, int prov_idx, int nav_dir,
809 VARIANT *out_node)
810{
811 HUIANODE tmp_node;
812 HRESULT hr;
813 VARIANT v;
814
815 hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, prov_idx, nav_dir, &v);
816 if (FAILED(hr))
817 return hr;
818
819 hr = UiaHUiaNodeFromVariant(&v, &tmp_node);
820 if (FAILED(hr))
821 goto exit;
822
823 while (1)
824 {
825 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)tmp_node);
826
827 /*
828 * If our sibling provider is the parent link of it's HUIANODE, then
829 * it is a valid sibling of this node.
830 */
831 if (node_creator_is_parent_link(node_data))
832 break;
833
834 /*
835 * If our sibling provider is not the parent link of it's HUIANODE, we
836 * need to try the next sibling.
837 */
838 hr = get_navigate_from_node_provider((IWineUiaNode *)tmp_node, node_data->creator_prov_idx, nav_dir, &v);
839 UiaNodeRelease(tmp_node);
840 if (FAILED(hr))
841 return hr;
842
843 tmp_node = NULL;
844 hr = UiaHUiaNodeFromVariant(&v, &tmp_node);
845 if (FAILED(hr))
846 break;
847 }
848
849exit:
850 if (tmp_node)
851 *out_node = v;
852
853 return S_OK;
854}
855
856static HRESULT get_child_for_node(struct uia_node *node, int start_prov_idx, int nav_dir, VARIANT *out_node)
857{
858 int prov_idx = start_prov_idx;
859 HUIANODE tmp_node = NULL;
860 HRESULT hr;
861 VARIANT v;
862
863 while ((prov_idx >= 0) && (prov_idx < node->prov_count))
864 {
865 struct uia_node *node_data;
866
867 hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, prov_idx, nav_dir, &v);
868 if (FAILED(hr))
869 return hr;
870
871 if (nav_dir == NavigateDirection_FirstChild)
872 prov_idx--;
873 else
874 prov_idx++;
875
876 /* If we failed to get a child, try the next provider. */
877 hr = UiaHUiaNodeFromVariant(&v, &tmp_node);
878 if (FAILED(hr))
879 continue;
880
881 node_data = impl_from_IWineUiaNode((IWineUiaNode *)tmp_node);
882
883 /* This child is the parent link of its node, so we can return it. */
884 if (node_creator_is_parent_link(node_data))
885 break;
886
887 /*
888 * If the first child provider isn't the parent link of it's HUIANODE,
889 * we need to check the child provider for any valid siblings.
890 */
891 if (nav_dir == NavigateDirection_FirstChild)
892 hr = get_sibling_from_node_provider(node_data, node_data->creator_prov_idx,
894 else
895 hr = get_sibling_from_node_provider(node_data, node_data->creator_prov_idx,
897
898 UiaNodeRelease(tmp_node);
899 if (FAILED(hr))
900 return hr;
901
902 /* If we got a valid sibling from the child provider, return it. */
903 hr = UiaHUiaNodeFromVariant(&v, &tmp_node);
904 if (SUCCEEDED(hr))
905 break;
906 }
907
908 if (tmp_node)
909 *out_node = v;
910
911 return S_OK;
912}
913
914HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node)
915{
916 HRESULT hr;
917 VARIANT v;
918
919 *out_node = NULL;
920
921 VariantInit(&v);
922 switch (nav_dir)
923 {
926 /* First child always comes from last provider index. */
927 if (nav_dir == NavigateDirection_FirstChild)
928 hr = get_child_for_node(node, node->prov_count - 1, nav_dir, &v);
929 else
930 hr = get_child_for_node(node, 0, nav_dir, &v);
931 if (FAILED(hr))
932 WARN("Child navigation failed with hr %#lx\n", hr);
933 break;
934
937 {
938 struct uia_node *node_data;
939 HUIANODE parent;
940 VARIANT tmp;
941
942 hr = get_sibling_from_node_provider(node, node->parent_link_idx, nav_dir, &v);
943 if (FAILED(hr))
944 {
945 WARN("Sibling navigation failed with hr %#lx\n", hr);
946 break;
947 }
948
949 if (V_VT(&v) != VT_EMPTY)
950 break;
951
952 hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx,
954 if (FAILED(hr))
955 {
956 WARN("Parent navigation failed with hr %#lx\n", hr);
957 break;
958 }
959
961 if (FAILED(hr))
962 break;
963
964 /*
965 * If the parent node has multiple providers, attempt to get a sibling
966 * from one of them.
967 */
968 node_data = impl_from_IWineUiaNode((IWineUiaNode *)parent);
969 if (node_data->prov_count > 1)
970 {
971 if (nav_dir == NavigateDirection_NextSibling)
973 else
975 }
976
978 break;
979 }
980
982 hr = get_navigate_from_node_provider(&node->IWineUiaNode_iface, node->parent_link_idx, nav_dir, &v);
983 if (FAILED(hr))
984 WARN("Parent navigation failed with hr %#lx\n", hr);
985 break;
986
987 default:
988 WARN("Invalid NavigateDirection %d\n", nav_dir);
989 return E_INVALIDARG;
990 }
991
992 if (V_VT(&v) != VT_EMPTY)
993 {
994 hr = UiaHUiaNodeFromVariant(&v, (HUIANODE *)out_node);
995 if (FAILED(hr))
996 WARN("UiaHUiaNodeFromVariant failed with hr %#lx\n", hr);
997 }
998
999 return S_OK;
1000}
1001
1002static HRESULT conditional_navigate_uia_node(struct uia_node *node, int nav_dir, struct UiaCondition *cond,
1003 HUIANODE *out_node)
1004{
1005 HRESULT hr;
1006
1007 *out_node = NULL;
1008 switch (nav_dir)
1009 {
1011 {
1012 struct uia_node *node_data = node;
1013 HUIANODE parent;
1014
1015 IWineUiaNode_AddRef(&node_data->IWineUiaNode_iface);
1016 while (1)
1017 {
1019 if (FAILED(hr) || !parent)
1020 break;
1021
1022 hr = uia_condition_check(parent, cond);
1023 if (FAILED(hr))
1024 {
1026 break;
1027 }
1028
1030 {
1031 *out_node = parent;
1032 break;
1033 }
1034
1035 IWineUiaNode_Release(&node_data->IWineUiaNode_iface);
1036 node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)parent);
1037 }
1038 IWineUiaNode_Release(&node_data->IWineUiaNode_iface);
1039 break;
1040 }
1041
1046 if (cond->ConditionType != ConditionType_True)
1047 {
1048 FIXME("ConditionType %d based navigation for dir %d is not implemented.\n", cond->ConditionType, nav_dir);
1049 return E_NOTIMPL;
1050 }
1051
1052 hr = navigate_uia_node(node, nav_dir, out_node);
1053 break;
1054
1055 default:
1056 WARN("Invalid NavigateDirection %d\n", nav_dir);
1057 return E_INVALIDARG;
1058 }
1059
1060 return hr;
1061}
1062
1063/*
1064 * Assuming we have a tree that looks like this:
1065 * +-------+
1066 * | |
1067 * | 1 |
1068 * | |
1069 * +---+---+
1070 * |
1071 * +-----------+-----------+
1072 * | | |
1073 * +---+---+ +---+---+ +---+---+
1074 * | | | | | |
1075 * | 2 +---| 3 +---+ 4 |
1076 * | | | | | |
1077 * +---+---+ +-------+ +-------+
1078 * |
1079 * +---+---+
1080 * | |
1081 * | 5 |
1082 * | |
1083 * +-------+
1084 * If we start navigation of the tree from node 1, our visit order for a
1085 * depth first search would be 1 -> 2 -> 5 -> 3 -> 4.
1086 *
1087 * However, if we start from the middle of the sequence at node 5 without the
1088 * prior context of navigating from nodes 1 and 2, we need to use the function
1089 * below to reach node 3, so we can visit the nodes within the tree in the
1090 * same order of 5 -> 3 -> 4.
1091 */
1092static HRESULT traverse_uia_node_tree_siblings(HUIANODE huianode, struct UiaCondition *ascending_stop_cond,
1093 int dir, BOOL at_root_level, HUIANODE *out_node)
1094{
1095 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
1096 HUIANODE node2 = NULL;
1097 HRESULT hr;
1098
1099 *out_node = NULL;
1100
1101 IWineUiaNode_AddRef(&node->IWineUiaNode_iface);
1102 while (1)
1103 {
1104 hr = navigate_uia_node(node, dir, &node2);
1105 if (FAILED(hr) || node2 || !at_root_level)
1106 break;
1107
1109 if (FAILED(hr) || !node2)
1110 break;
1111
1112 hr = uia_condition_check(node2, ascending_stop_cond);
1114 {
1115 UiaNodeRelease(node2);
1116 node2 = NULL;
1117 break;
1118 }
1119
1120 IWineUiaNode_Release(&node->IWineUiaNode_iface);
1121 node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node2);
1122 }
1123
1124 IWineUiaNode_Release(&node->IWineUiaNode_iface);
1125 *out_node = node2;
1126
1127 return hr;
1128}
1129
1130/*
1131 * This function is used to traverse the 'raw' tree of HUIANODEs using a
1132 * depth-first search. As each node in the tree is visited, it is checked
1133 * against two conditions.
1134 *
1135 * The first is the view condition, which is a filter for what is considered to
1136 * be a valid node in the current tree 'view'. The view condition essentially
1137 * creates a sort of 'virtual' tree. UI Automation provides three default tree
1138 * views:
1139 * -The 'raw' view has the view condition as ConditionType_True, so the tree
1140 * is completely unfiltered. All nodes are valid.
1141 * -The 'control' view contains only nodes that do not return VARIANT_FALSE
1142 * for UIA_IsControlElementPropertyId.
1143 * -The 'content' view contains only nodes that do not return VARIANT_FALSE
1144 * for both UIA_IsControlElementPropertyId and UIA_IsContentElementPropertyId.
1145 *
1146 * If the currently visited node is considered to be valid within our view
1147 * condition, it is then checked against the search condition to determine if
1148 * it should be returned.
1149 */
1150static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *view_cond,
1151 struct UiaCondition *search_cond, struct UiaCondition *pre_sibling_nav_stop_cond,
1152 struct UiaCondition *ascending_stop_cond, int traversal_opts, BOOL at_root_level, BOOL find_first,
1153 BOOL *root_found, int max_depth, int *cur_depth, struct uia_node_array *out_nodes)
1154{
1155 HUIANODE node = huianode;
1156 HRESULT hr;
1157
1158 while (1)
1159 {
1160 struct uia_node *node_data = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)node);
1161 BOOL incr_depth = FALSE;
1162 HUIANODE node2 = NULL;
1163
1164 hr = uia_condition_check(node, view_cond);
1165 if (FAILED(hr))
1166 break;
1167
1169 {
1170 /*
1171 * If this is a valid node within our treeview, we need to increment
1172 * our current depth within the tree.
1173 */
1174 incr_depth = TRUE;
1175
1176 if (*root_found)
1177 {
1178 hr = uia_condition_check(node, search_cond);
1179 if (FAILED(hr))
1180 break;
1181
1183 {
1184 hr = add_node_to_node_array(out_nodes, node);
1185 if (FAILED(hr))
1186 break;
1187
1188 if (find_first)
1189 {
1190 hr = S_FALSE;
1191 break;
1192 }
1193 }
1194 }
1195
1196 *root_found = TRUE;
1197 }
1198
1199 if (incr_depth)
1200 (*cur_depth)++;
1201
1202 /* If we haven't exceeded our maximum traversal depth, visit children of this node. */
1203 if (max_depth < 0 || (*cur_depth) <= max_depth)
1204 {
1205 if (traversal_opts & TreeTraversalOptions_LastToFirstOrder)
1206 hr = navigate_uia_node(node_data, NavigateDirection_LastChild, &node2);
1207 else
1209
1210 if (SUCCEEDED(hr) && node2)
1211 hr = traverse_uia_node_tree(node2, view_cond, search_cond, pre_sibling_nav_stop_cond, ascending_stop_cond,
1212 traversal_opts, FALSE, find_first, root_found, max_depth, cur_depth, out_nodes);
1213
1214 if (FAILED(hr) || hr == S_FALSE)
1215 break;
1216 }
1217
1218 if (incr_depth)
1219 (*cur_depth)--;
1220
1221 /*
1222 * Before attempting to visit any siblings of huianode, make sure
1223 * huianode doesn't match our stop condition.
1224 */
1225 hr = uia_condition_check(node, pre_sibling_nav_stop_cond);
1227 break;
1228
1229 /* Now, check for any siblings to visit. */
1230 if (traversal_opts & TreeTraversalOptions_LastToFirstOrder)
1232 at_root_level, &node2);
1233 else
1235 at_root_level, &node2);
1236
1237 if (FAILED(hr) || !node2)
1238 break;
1239
1241 node = node2;
1242 }
1243
1245
1246 return hr;
1247}
1248
1249static HRESULT bstrcat_realloc(BSTR *bstr, const WCHAR *cat_str)
1250{
1251 if (!SysReAllocStringLen(bstr, NULL, SysStringLen(*bstr) + lstrlenW(cat_str)))
1252 {
1253 SysFreeString(*bstr);
1254 *bstr = NULL;
1255 return E_OUTOFMEMORY;
1256 }
1257
1258 lstrcatW(*bstr, cat_str);
1259 return S_OK;
1260}
1261
1262static const WCHAR *prov_desc_type_str[] = {
1263 L"Override",
1264 L"Main",
1265 L"Nonclient",
1266 L"Hwnd",
1267};
1268
1270{
1271 const struct uia_prop_info *prop_info = uia_prop_info_from_id(UIA_ProviderDescriptionPropertyId);
1272 WCHAR buf[256] = { 0 };
1273 HRESULT hr = S_OK;
1274 BSTR node_desc;
1275 int i;
1276
1277 VariantInit(out_desc);
1278
1279 /*
1280 * If we have a single provider, and it's a nested node provider, we just
1281 * return the string directly from the nested node.
1282 */
1283 if ((node->prov_count == 1) && is_nested_node_provider(node->prov[get_node_provider_type_at_idx(node, 0)]))
1284 return get_prop_val_from_node_provider(&node->IWineUiaNode_iface, prop_info, 0, out_desc);
1285
1286 wsprintfW(buf, L"[pid:%d,providerId:%#x ", GetCurrentProcessId(), node->hwnd);
1287 if (!(node_desc = SysAllocString(buf)))
1288 return E_OUTOFMEMORY;
1289
1290 for (i = 0; i < node->prov_count; i++)
1291 {
1292 int prov_type = get_node_provider_type_at_idx(node, i);
1293 VARIANT v;
1294
1295 buf[0] = 0;
1296 /* There's a provider preceding this one, add a "; " separator. */
1297 if (i)
1298 lstrcatW(buf, L"; ");
1299
1300 /* Generate the provider type prefix string. */
1301 lstrcatW(buf, prov_desc_type_str[prov_type]);
1302 if (node->parent_link_idx == i)
1303 lstrcatW(buf, L"(parent link)");
1304 lstrcatW(buf, L":");
1305 if (is_nested_node_provider(node->prov[prov_type]))
1306 lstrcatW(buf, L"Nested ");
1307
1308 hr = bstrcat_realloc(&node_desc, buf);
1309 if (FAILED(hr))
1310 goto exit;
1311
1312 VariantInit(&v);
1313 hr = get_prop_val_from_node_provider(&node->IWineUiaNode_iface, prop_info, i, &v);
1314 if (FAILED(hr))
1315 goto exit;
1316
1317 hr = bstrcat_realloc(&node_desc, V_BSTR(&v));
1318 VariantClear(&v);
1319 if (FAILED(hr))
1320 goto exit;
1321 }
1322
1323 hr = bstrcat_realloc(&node_desc, L"]");
1324 if (SUCCEEDED(hr))
1325 {
1326 V_VT(out_desc) = VT_BSTR;
1327 V_BSTR(out_desc) = node_desc;
1328 }
1329
1330exit:
1331 if (FAILED(hr))
1332 SysFreeString(node_desc);
1333
1334 return hr;
1335}
1336
1338{
1339 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1340 HRESULT hr = S_OK;
1341 int i;
1342
1343 for (i = 0; i < node_data->prov_count; i++)
1344 {
1345 hr = attach_event_to_node_provider(&node_data->IWineUiaNode_iface, i, (HUIAEVENT)event);
1346 if (FAILED(hr))
1347 return hr;
1348 }
1349
1350 return hr;
1351}
1352
1353/*
1354 * IWineUiaProvider interface.
1355 */
1356static HRESULT WINAPI uia_provider_QueryInterface(IWineUiaProvider *iface, REFIID riid, void **ppv)
1357{
1358 *ppv = NULL;
1359 if (IsEqualIID(riid, &IID_IWineUiaProvider) || IsEqualIID(riid, &IID_IUnknown))
1360 *ppv = iface;
1361 else
1362 return E_NOINTERFACE;
1363
1364 IWineUiaProvider_AddRef(iface);
1365 return S_OK;
1366}
1367
1368static ULONG WINAPI uia_provider_AddRef(IWineUiaProvider *iface)
1369{
1370 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1372
1373 TRACE("%p, refcount %ld\n", prov, ref);
1374 return ref;
1375}
1376
1377static void uia_stop_client_thread(void);
1378static ULONG WINAPI uia_provider_Release(IWineUiaProvider *iface)
1379{
1380 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1382
1383 TRACE("%p, refcount %ld\n", prov, ref);
1384 if (!ref)
1385 {
1386 IRawElementProviderSimple_Release(prov->elprov);
1387 free(prov);
1388 }
1389
1390 return ref;
1391}
1392
1393static HRESULT get_variant_for_elprov_node(IRawElementProviderSimple *elprov, BOOL out_nested,
1394 BOOL refuse_hwnd_providers, VARIANT *v)
1395{
1396 HUIANODE node;
1397 HRESULT hr;
1398
1399 VariantInit(v);
1400
1401 hr = create_uia_node_from_elprov(elprov, &node, !refuse_hwnd_providers, 0);
1402 IRawElementProviderSimple_Release(elprov);
1403 if (SUCCEEDED(hr))
1404 {
1405 if (out_nested)
1406 {
1408
1409 if (!lr)
1410 return E_FAIL;
1411
1412 V_VT(v) = VT_I4;
1413 V_I4(v) = lr;
1414 }
1415 else
1417 }
1418
1419 return S_OK;
1420}
1421
1423 const struct uia_prop_info *prop_info, VARIANT *ret_val)
1424{
1425 HRESULT hr;
1426 VARIANT v;
1427
1428 VariantInit(&v);
1429 hr = IRawElementProviderSimple_GetPropertyValue(prov->elprov, prop_info->prop_id, &v);
1430 if (FAILED(hr))
1431 goto exit;
1432
1433 switch (prop_info->type)
1434 {
1435 case UIAutomationType_Int:
1436 if (V_VT(&v) != VT_I4)
1437 {
1438 WARN("Invalid vt %d for UIAutomationType_Int\n", V_VT(&v));
1439 goto exit;
1440 }
1441 *ret_val = v;
1442 break;
1443
1444 case UIAutomationType_IntArray:
1445 if (V_VT(&v) != (VT_I4 | VT_ARRAY))
1446 {
1447 WARN("Invalid vt %d for UIAutomationType_IntArray\n", V_VT(&v));
1448 goto exit;
1449 }
1450 *ret_val = v;
1451 break;
1452
1453 case UIAutomationType_Double:
1454 if (V_VT(&v) != VT_R8)
1455 {
1456 WARN("Invalid vt %d for UIAutomationType_Double\n", V_VT(&v));
1457 goto exit;
1458 }
1459 *ret_val = v;
1460 break;
1461
1462 case UIAutomationType_DoubleArray:
1463 if (V_VT(&v) != (VT_R8 | VT_ARRAY))
1464 {
1465 WARN("Invalid vt %d for UIAutomationType_DoubleArray\n", V_VT(&v));
1466 goto exit;
1467 }
1468 *ret_val = v;
1469 break;
1470
1471 case UIAutomationType_Bool:
1472 if (V_VT(&v) != VT_BOOL)
1473 {
1474 WARN("Invalid vt %d for UIAutomationType_Bool\n", V_VT(&v));
1475 goto exit;
1476 }
1477 *ret_val = v;
1478 break;
1479
1480 case UIAutomationType_String:
1481 if (V_VT(&v) != VT_BSTR)
1482 {
1483 WARN("Invalid vt %d for UIAutomationType_String\n", V_VT(&v));
1484 goto exit;
1485 }
1486 *ret_val = v;
1487 break;
1488
1489 case UIAutomationType_Element:
1490 {
1491 IRawElementProviderSimple *elprov;
1492
1493 if (V_VT(&v) != VT_UNKNOWN)
1494 {
1495 WARN("Invalid vt %d for UIAutomationType_Element\n", V_VT(&v));
1496 goto exit;
1497 }
1498
1499 hr = IUnknown_QueryInterface(V_UNKNOWN(&v), &IID_IRawElementProviderSimple,
1500 (void **)&elprov);
1501 VariantClear(&v);
1502 if (FAILED(hr))
1503 goto exit;
1504
1506 if (FAILED(hr))
1507 return hr;
1508
1509 break;
1510 }
1511
1512 case UIAutomationType_ElementArray:
1513 if (V_VT(&v) != (VT_UNKNOWN | VT_ARRAY))
1514 {
1515 WARN("Invalid vt %d for UIAutomationType_ElementArray\n", V_VT(&v));
1516 goto exit;
1517 }
1518 create_uia_node_safearray(&v, ret_val);
1519 if (V_VT(ret_val) == (VT_UINT_PTR | VT_ARRAY))
1520 VariantClear(&v);
1521 break;
1522
1523 default:
1524 break;
1525 }
1526
1527exit:
1528 if (V_VT(ret_val) == VT_EMPTY)
1529 VariantClear(&v);
1530
1531 return S_OK;
1532}
1533
1536 const struct uia_prop_info *prop_info, VARIANT *ret_val)
1537{
1538 HRESULT hr;
1539
1540 switch (prop_info->prop_id)
1541 {
1542 case UIA_RuntimeIdPropertyId:
1543 {
1544 IRawElementProviderFragment *elfrag;
1545 SAFEARRAY *sa = NULL;
1546 LONG lbound;
1547 int val;
1548
1549 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
1550 if (FAILED(hr) || !elfrag)
1551 break;
1552
1553 hr = IRawElementProviderFragment_GetRuntimeId(elfrag, &sa);
1554 IRawElementProviderFragment_Release(elfrag);
1555 if (FAILED(hr) || !sa)
1556 break;
1557
1558 hr = SafeArrayGetLBound(sa, 1, &lbound);
1559 if (FAILED(hr))
1560 {
1562 break;
1563 }
1564
1565 hr = SafeArrayGetElement(sa, &lbound, &val);
1566 if (FAILED(hr))
1567 {
1569 break;
1570 }
1571
1572 if (val == UiaAppendRuntimeId)
1573 {
1574 enum ProviderOptions prov_opts = 0;
1575 IRawElementProviderSimple *elprov;
1576 HWND hwnd;
1577
1579 if (!elprov)
1580 {
1582 return E_FAIL;
1583 }
1584
1585 hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts);
1586 IRawElementProviderSimple_Release(elprov);
1587 if (FAILED(hr))
1588 WARN("get_ProviderOptions for root provider failed with %#lx\n", hr);
1589
1590 if (!(sa = append_uia_runtime_id(sa, hwnd, prov_opts)))
1591 break;
1592 }
1593
1594 V_VT(ret_val) = VT_I4 | VT_ARRAY;
1595 V_ARRAY(ret_val) = sa;
1596 break;
1597 }
1598
1599 case UIA_BoundingRectanglePropertyId:
1600 {
1601 IRawElementProviderFragment *elfrag;
1602 struct UiaRect rect = { 0 };
1603 double rect_vals[4];
1604 SAFEARRAY *sa;
1605 LONG idx;
1606
1607 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
1608 if (FAILED(hr) || !elfrag)
1609 break;
1610
1611 hr = IRawElementProviderFragment_get_BoundingRectangle(elfrag, &rect);
1612 IRawElementProviderFragment_Release(elfrag);
1613 if (FAILED(hr) || (rect.width <= 0 || rect.height <= 0))
1614 break;
1615
1616 if (!(sa = SafeArrayCreateVector(VT_R8, 0, ARRAY_SIZE(rect_vals))))
1617 break;
1618
1619 rect_vals[0] = rect.left;
1620 rect_vals[1] = rect.top;
1621 rect_vals[2] = rect.width;
1622 rect_vals[3] = rect.height;
1623 for (idx = 0; idx < ARRAY_SIZE(rect_vals); idx++)
1624 {
1625 hr = SafeArrayPutElement(sa, &idx, &rect_vals[idx]);
1626 if (FAILED(hr))
1627 {
1629 break;
1630 }
1631 }
1632
1633 V_VT(ret_val) = VT_R8 | VT_ARRAY;
1634 V_ARRAY(ret_val) = sa;
1635 break;
1636 }
1637
1638 case UIA_ProviderDescriptionPropertyId:
1639 {
1640 /* FIXME: Get actual name of the executable our provider comes from. */
1641 static const WCHAR *provider_origin = L" (unmanaged:uiautomationcore.dll)";
1642 static const WCHAR *default_desc = L"Unidentified provider";
1643 BSTR prov_desc_str;
1644 VARIANT v;
1645
1646 hr = uia_provider_get_elem_prop_val(prov, prop_info, &v);
1647 if (FAILED(hr))
1648 return hr;
1649
1650 if (V_VT(&v) == VT_BSTR)
1651 prov_desc_str = SysAllocStringLen(V_BSTR(&v), lstrlenW(V_BSTR(&v)) + lstrlenW(provider_origin));
1652 else
1653 prov_desc_str = SysAllocStringLen(default_desc, lstrlenW(default_desc) + lstrlenW(provider_origin));
1654
1655 VariantClear(&v);
1656 if (!prov_desc_str)
1657 return E_OUTOFMEMORY;
1658
1659 /* Append the name of the executable our provider comes from. */
1660 wsprintfW(&prov_desc_str[lstrlenW(prov_desc_str)], L"%s", provider_origin);
1661 V_VT(ret_val) = VT_BSTR;
1662 V_BSTR(ret_val) = prov_desc_str;
1663 break;
1664 }
1665
1666 default:
1667 break;
1668 }
1669
1670 return S_OK;
1671}
1672
1674 const struct uia_prop_info *prop_info, VARIANT *ret_val)
1675{
1676 const struct uia_pattern_info *pattern_info = uia_pattern_info_from_id(prop_info->pattern_id);
1677 IUnknown *unk, *pattern_prov;
1678 HRESULT hr;
1679
1680 unk = pattern_prov = NULL;
1681 hr = IRawElementProviderSimple_GetPatternProvider(prov->elprov, prop_info->pattern_id, &unk);
1682 if (FAILED(hr) || !unk)
1683 return S_OK;
1684
1685 hr = IUnknown_QueryInterface(unk, pattern_info->pattern_iid, (void **)&pattern_prov);
1686 IUnknown_Release(unk);
1687 if (FAILED(hr) || !pattern_prov)
1688 {
1689 WARN("Failed to get pattern interface from object\n");
1690 return S_OK;
1691 }
1692
1693 switch (prop_info->prop_id)
1694 {
1695 case UIA_ValueIsReadOnlyPropertyId:
1696 {
1697 BOOL val;
1698
1699 hr = IValueProvider_get_IsReadOnly((IValueProvider *)pattern_prov, &val);
1700 if (SUCCEEDED(hr))
1701 variant_init_bool(ret_val, val);
1702 break;
1703 }
1704
1705 case UIA_LegacyIAccessibleChildIdPropertyId:
1706 {
1707 int val;
1708
1709 hr = ILegacyIAccessibleProvider_get_ChildId((ILegacyIAccessibleProvider *)pattern_prov, &val);
1710 if (SUCCEEDED(hr))
1711 variant_init_i4(ret_val, val);
1712 break;
1713 }
1714
1715 case UIA_LegacyIAccessibleRolePropertyId:
1716 {
1717 DWORD val;
1718
1719 hr = ILegacyIAccessibleProvider_get_Role((ILegacyIAccessibleProvider *)pattern_prov, &val);
1720 if (SUCCEEDED(hr))
1721 variant_init_i4(ret_val, val);
1722 break;
1723 }
1724
1725 default:
1726 break;
1727 }
1728
1729 IUnknown_Release(pattern_prov);
1730 return S_OK;
1731}
1732
1733static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface,
1734 const struct uia_prop_info *prop_info, VARIANT *ret_val)
1735{
1736 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1737
1738 TRACE("%p, %p, %p\n", iface, prop_info, ret_val);
1739
1740 VariantInit(ret_val);
1741 switch (prop_info->prop_type)
1742 {
1744 return uia_provider_get_elem_prop_val(prov, prop_info, ret_val);
1745
1746 case PROP_TYPE_SPECIAL:
1747 return uia_provider_get_special_prop_val(prov, prop_info, ret_val);
1748
1750 return uia_provider_get_pattern_prop_val(prov, prop_info, ret_val);
1751
1752 default:
1753 break;
1754 }
1755
1756 return S_OK;
1757}
1758
1759static HRESULT WINAPI uia_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts)
1760{
1761 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1762 enum ProviderOptions prov_opts;
1763 HRESULT hr;
1764
1765 TRACE("%p, %p\n", iface, out_opts);
1766
1767 *out_opts = 0;
1768 hr = IRawElementProviderSimple_get_ProviderOptions(prov->elprov, &prov_opts);
1769 if (SUCCEEDED(hr))
1770 *out_opts = prov_opts;
1771
1772 return S_OK;
1773}
1774
1775static HRESULT WINAPI uia_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val)
1776{
1777 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1778
1779 TRACE("%p, %p\n", iface, out_val);
1780
1781 if (!prov->parent_check_ran)
1782 {
1783 IRawElementProviderFragment *elfrag, *elfrag2;
1784 HRESULT hr;
1785
1786 prov->has_parent = FALSE;
1787 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
1788 if (SUCCEEDED(hr) && elfrag)
1789 {
1790 hr = IRawElementProviderFragment_Navigate(elfrag, NavigateDirection_Parent, &elfrag2);
1791 IRawElementProviderFragment_Release(elfrag);
1792 if (SUCCEEDED(hr) && elfrag2)
1793 {
1794 prov->has_parent = TRUE;
1795 IRawElementProviderFragment_Release(elfrag2);
1796 }
1797 }
1798
1799 prov->parent_check_ran = TRUE;
1800 }
1801
1802 *out_val = prov->has_parent;
1803
1804 return S_OK;
1805}
1806
1807static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val)
1808{
1809 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1810 IRawElementProviderFragment *elfrag, *elfrag2;
1811 HRESULT hr;
1812
1813 TRACE("%p, %d, %p\n", iface, nav_dir, out_val);
1814
1815 VariantInit(out_val);
1816 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
1817 if (FAILED(hr) || !elfrag)
1818 return S_OK;
1819
1820 hr = IRawElementProviderFragment_Navigate(elfrag, nav_dir, &elfrag2);
1821 IRawElementProviderFragment_Release(elfrag);
1822 if (SUCCEEDED(hr) && elfrag2)
1823 {
1824 IRawElementProviderSimple *elprov;
1825
1826 hr = IRawElementProviderFragment_QueryInterface(elfrag2, &IID_IRawElementProviderSimple, (void **)&elprov);
1827 IRawElementProviderFragment_Release(elfrag2);
1828 if (FAILED(hr) || !elprov)
1829 return hr;
1830
1832 if (FAILED(hr))
1833 return hr;
1834 }
1835
1836 return S_OK;
1837}
1838
1839static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
1840{
1841 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1842 IRawElementProviderFragmentRoot *elroot;
1843 IRawElementProviderFragment *elfrag;
1844 IRawElementProviderSimple *elprov;
1845 HRESULT hr;
1846
1847 TRACE("%p, %#lx, %p\n", iface, flags, out_val);
1848
1850 FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
1851
1852 VariantInit(out_val);
1853 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragmentRoot, (void **)&elroot);
1854 if (FAILED(hr))
1855 return S_OK;
1856
1857 hr = IRawElementProviderFragmentRoot_GetFocus(elroot, &elfrag);
1858 IRawElementProviderFragmentRoot_Release(elroot);
1859 if (FAILED(hr) || !elfrag)
1860 return hr;
1861
1862 hr = IRawElementProviderFragment_QueryInterface(elfrag, &IID_IRawElementProviderSimple, (void **)&elprov);
1863 IRawElementProviderFragment_Release(elfrag);
1864 if (SUCCEEDED(hr))
1865 {
1867 if (FAILED(hr))
1868 VariantClear(out_val);
1869 }
1870
1871 return hr;
1872}
1873
1874static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
1875{
1876 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1877 struct uia_event *event = (struct uia_event *)huiaevent;
1878 IRawElementProviderFragmentRoot *elroot = NULL;
1879 IRawElementProviderFragment *elfrag;
1880 SAFEARRAY *embedded_roots = NULL;
1881 HRESULT hr;
1882
1883 TRACE("%p, %#Ix\n", iface, huiaevent);
1884
1885 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderFragment, (void **)&elfrag);
1886 if (FAILED(hr))
1887 return S_OK;
1888
1889 hr = IRawElementProviderFragment_get_FragmentRoot(elfrag, &elroot);
1890 if (FAILED(hr))
1891 goto exit;
1892
1893 /*
1894 * For now, we only support embedded fragment roots on providers that
1895 * don't represent a nested node.
1896 */
1898 {
1899 hr = IRawElementProviderFragment_GetEmbeddedFragmentRoots(elfrag, &embedded_roots);
1900 if (FAILED(hr))
1901 WARN("GetEmbeddedFragmentRoots failed with hr %#lx\n", hr);
1902 }
1903
1904 if (elroot)
1905 {
1906 IProxyProviderWinEventHandler *winevent_handler;
1907 IRawElementProviderAdviseEvents *advise_events;
1908
1909 if (!prov->return_nested_node && SUCCEEDED(IRawElementProviderFragmentRoot_QueryInterface(elroot,
1910 &IID_IProxyProviderWinEventHandler, (void **)&winevent_handler)))
1911 {
1913 if (FAILED(hr))
1914 WARN("Failed to add hwnd for win_event, hr %#lx\n", hr);
1915 IProxyProviderWinEventHandler_Release(winevent_handler);
1916 }
1917 else if (SUCCEEDED(IRawElementProviderFragmentRoot_QueryInterface(elroot, &IID_IRawElementProviderAdviseEvents,
1918 (void **)&advise_events)))
1919 {
1921 IRawElementProviderAdviseEvents_Release(advise_events);
1922 if (FAILED(hr))
1923 goto exit;
1924 }
1925 }
1926
1927 if (embedded_roots)
1928 {
1929 LONG lbound, elems, i;
1930 HUIANODE node;
1931
1932 hr = get_safearray_bounds(embedded_roots, &lbound, &elems);
1933 if (FAILED(hr))
1934 goto exit;
1935
1936 for (i = 0; i < elems; i++)
1937 {
1938 IRawElementProviderSimple *elprov;
1939 IUnknown *unk;
1940 LONG idx;
1941
1942 idx = lbound + i;
1943 hr = SafeArrayGetElement(embedded_roots, &idx, &unk);
1944 if (FAILED(hr))
1945 goto exit;
1946
1947 hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov);
1948 IUnknown_Release(unk);
1949 if (FAILED(hr))
1950 goto exit;
1951
1953 IRawElementProviderSimple_Release(elprov);
1954 if (SUCCEEDED(hr))
1955 {
1958 if (FAILED(hr))
1959 {
1960 WARN("attach_event_to_uia_node failed with hr %#lx\n", hr);
1961 goto exit;
1962 }
1963 }
1964 }
1965 }
1966
1967exit:
1968 if (elroot)
1969 IRawElementProviderFragmentRoot_Release(elroot);
1970 IRawElementProviderFragment_Release(elfrag);
1971 SafeArrayDestroy(embedded_roots);
1972
1973 return hr;
1974}
1975
1976static HRESULT WINAPI uia_provider_respond_to_win_event(IWineUiaProvider *iface, DWORD win_event, ULONG hwnd, LONG obj_id,
1977 LONG child_id, IProxyProviderWinEventSink *sink)
1978{
1979 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1980 IProxyProviderWinEventHandler *handler;
1981 HRESULT hr;
1982
1983 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IProxyProviderWinEventHandler, (void **)&handler);
1984 if (FAILED(hr))
1985 return S_OK;
1986
1987 hr = IProxyProviderWinEventHandler_RespondToWinEvent(handler, win_event, UlongToHandle(hwnd), obj_id, child_id, sink);
1988 IProxyProviderWinEventHandler_Release(handler);
1989
1990 return hr;
1991}
1992
1993static HRESULT WINAPI uia_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
1994{
1995 struct uia_provider *prov = impl_from_IWineUiaProvider(iface);
1996 IRawElementProviderSimple *elprov;
1997 HRESULT hr;
1998
1999 TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
2000
2002 FIXME("PROV_METHOD_FLAG_RETURN_NODE_LRES ignored for normal providers.\n");
2003
2004 VariantInit(ret_val);
2005 hr = IRawElementProviderSimple_QueryInterface(prov->elprov, &IID_IRawElementProviderSimple, (void **)&elprov);
2006 if (FAILED(hr))
2007 return hr;
2008
2009 /* get_variant_for_elprov_node will release our provider upon failure. */
2011}
2012
2013static const IWineUiaProviderVtbl uia_provider_vtbl = {
2025};
2026
2027static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov,
2028 int prov_type)
2029{
2030 struct uia_provider *prov = calloc(1, sizeof(*prov));
2031
2032 if (!prov)
2033 return E_OUTOFMEMORY;
2034
2036 prov->elprov = elprov;
2037 prov->ref = 1;
2038 prov->hwnd = node->hwnd;
2039 node->prov[prov_type] = &prov->IWineUiaProvider_iface;
2040 if (!node->prov_count)
2041 node->creator_prov_type = prov_type;
2042 node->prov_count++;
2043
2044 IRawElementProviderSimple_AddRef(elprov);
2045 return S_OK;
2046}
2047
2049HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node,
2050 BOOL get_hwnd_providers, int node_flags)
2051{
2052 static const int unsupported_prov_opts = ProviderOptions_ProviderOwnsSetFocus | ProviderOptions_HasNativeIAccessible |
2054 enum ProviderOptions prov_opts;
2055 struct uia_node *node;
2056 int prov_type;
2057 HRESULT hr;
2058
2059 *out_node = NULL;
2060
2061 hr = IRawElementProviderSimple_get_ProviderOptions(elprov, &prov_opts);
2062 if (FAILED(hr))
2063 return hr;
2064
2065 if (prov_opts & unsupported_prov_opts)
2066 FIXME("Ignoring unsupported ProviderOption(s) %#x\n", prov_opts & unsupported_prov_opts);
2067
2068 if (prov_opts & ProviderOptions_OverrideProvider)
2069 prov_type = PROV_TYPE_OVERRIDE;
2070 else if (prov_opts & ProviderOptions_NonClientAreaProvider)
2071 prov_type = PROV_TYPE_NONCLIENT;
2072 else if (prov_opts & ProviderOptions_ServerSideProvider)
2073 prov_type = PROV_TYPE_MAIN;
2074 else if (prov_opts & ProviderOptions_ClientSideProvider)
2075 prov_type = PROV_TYPE_HWND;
2076 else
2077 prov_type = PROV_TYPE_MAIN;
2078
2079 hr = create_uia_node(&node, node_flags);
2080 if (FAILED(hr))
2081 return hr;
2082
2083 node->hwnd = get_hwnd_from_provider(elprov);
2084
2085 hr = create_wine_uia_provider(node, elprov, prov_type);
2086 if (FAILED(hr))
2087 {
2088 free(node);
2089 return hr;
2090 }
2091
2092 if (node->hwnd && get_hwnd_providers)
2093 {
2095 if (FAILED(hr))
2096 WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr);
2097 }
2098
2100 if (FAILED(hr))
2101 {
2102 IWineUiaNode_Release(&node->IWineUiaNode_iface);
2103 return hr;
2104 }
2105
2106 *out_node = (void *)&node->IWineUiaNode_iface;
2107
2108 return S_OK;
2109}
2110
2111/***********************************************************************
2112 * UiaNodeFromProvider (uiautomationcore.@)
2113 */
2114HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *huianode)
2115{
2116 TRACE("(%p, %p)\n", elprov, huianode);
2117
2118 if (!elprov || !huianode)
2119 return E_INVALIDARG;
2120
2121 return create_uia_node_from_elprov(elprov, huianode, TRUE, 0);
2122}
2123
2124/*
2125 * UI Automation client thread functions.
2126 */
2128{
2129 CO_MTA_USAGE_COOKIE mta_cookie;
2133};
2134
2138};
2139
2143{
2144 0, 0, &client_thread_cs,
2146 0, 0, { (DWORD_PTR)(__FILE__ ": client_thread_cs") }
2147};
2148static CRITICAL_SECTION client_thread_cs = { &client_thread_cs_debug, -1, 0, 0, 0, 0 };
2149
2150#define WM_UIA_CLIENT_GET_NODE_PROV (WM_USER + 1)
2151#define WM_UIA_CLIENT_THREAD_STOP (WM_USER + 2)
2154 LPARAM lparam)
2155{
2156 switch (msg)
2157 {
2159 {
2161 return create_wine_uia_nested_node_provider((struct uia_node *)lparam, args->lr, args->unwrap);
2162 }
2163
2164 default:
2165 break;
2166 }
2167
2168 return DefWindowProcW(hwnd, msg, wparam, lparam);
2169}
2170
2172{
2173 HANDLE initialized_event = arg;
2174 HWND hwnd;
2175 MSG msg;
2176
2177 hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
2178 if (!hwnd)
2179 {
2180 WARN("CreateWindow failed: %ld\n", GetLastError());
2182 }
2183
2185 client_thread.hwnd = hwnd;
2186
2187 /* Initialization complete, thread can now process window messages. */
2188 SetEvent(initialized_event);
2189 TRACE("Client thread started.\n");
2190 while (GetMessageW(&msg, NULL, 0, 0))
2191 {
2192 if (msg.message == WM_UIA_CLIENT_THREAD_STOP)
2193 break;
2196 }
2197
2198 TRACE("Shutting down UI Automation client thread.\n");
2199
2202}
2203
2205{
2206 BOOL started = TRUE;
2207
2209 if (++client_thread.ref == 1)
2210 {
2211 HANDLE ready_event = NULL;
2212 HANDLE events[2];
2214 DWORD wait_obj;
2215 HRESULT hr;
2216
2217 /*
2218 * We use CoIncrementMTAUsage here instead of CoInitialize because it
2219 * allows us to exit the implicit MTA immediately when the thread
2220 * reference count hits 0, rather than waiting for the thread to
2221 * shutdown and call CoUninitialize like the provider thread.
2222 */
2223 hr = CoIncrementMTAUsage(&client_thread.mta_cookie);
2224 if (FAILED(hr))
2225 {
2226 started = FALSE;
2227 goto exit;
2228 }
2229
2230 /* Increment DLL reference count. */
2231 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2233
2234 events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2236 ready_event, 0, NULL)))
2237 {
2239 started = FALSE;
2240 goto exit;
2241 }
2242
2243 events[1] = client_thread.hthread;
2245 if (wait_obj != WAIT_OBJECT_0)
2246 {
2247 CloseHandle(client_thread.hthread);
2248 started = FALSE;
2249 }
2250
2251exit:
2252 if (ready_event)
2253 CloseHandle(ready_event);
2254 if (!started)
2255 {
2256 WARN("Failed to start client thread\n");
2257 if (client_thread.mta_cookie)
2259 memset(&client_thread, 0, sizeof(client_thread));
2260 }
2261 }
2262
2264 return started;
2265}
2266
2267static void uia_stop_client_thread(void)
2268{
2270 if (!--client_thread.ref)
2271 {
2274 CloseHandle(client_thread.hthread);
2275 memset(&client_thread, 0, sizeof(client_thread));
2276 }
2278}
2279
2280/*
2281 * IWineUiaProvider interface for nested node providers.
2282 *
2283 * Nested node providers represent an HUIANODE that resides in another
2284 * thread or process. We retrieve values from this HUIANODE through the
2285 * IWineUiaNode interface.
2286 */
2288 IWineUiaProvider IWineUiaProvider_iface;
2290
2291 IWineUiaNode *nested_node;
2292};
2293
2294static inline struct uia_nested_node_provider *impl_from_nested_node_IWineUiaProvider(IWineUiaProvider *iface)
2295{
2297}
2298
2300{
2301 *ppv = NULL;
2302 if (IsEqualIID(riid, &IID_IWineUiaProvider) || IsEqualIID(riid, &IID_IUnknown))
2303 *ppv = iface;
2304 else
2305 return E_NOINTERFACE;
2306
2307 IWineUiaProvider_AddRef(iface);
2308 return S_OK;
2309}
2310
2311static ULONG WINAPI uia_nested_node_provider_AddRef(IWineUiaProvider *iface)
2312{
2315
2316 TRACE("%p, refcount %ld\n", prov, ref);
2317 return ref;
2318}
2319
2320static ULONG WINAPI uia_nested_node_provider_Release(IWineUiaProvider *iface)
2321{
2324
2325 TRACE("%p, refcount %ld\n", prov, ref);
2326 if (!ref)
2327 {
2328 IWineUiaNode_Release(prov->nested_node);
2330 free(prov);
2331 }
2332
2333 return ref;
2334}
2335
2337 const struct uia_prop_info *prop_info, VARIANT *ret_val)
2338{
2340 HRESULT hr;
2341 VARIANT v;
2342
2343 TRACE("%p, %p, %p\n", iface, prop_info, ret_val);
2344
2345 VariantInit(ret_val);
2346 if (prop_info->type == UIAutomationType_ElementArray)
2347 {
2348 FIXME("Element array property types currently unsupported for nested nodes.\n");
2349 return E_NOTIMPL;
2350 }
2351
2352 hr = IWineUiaNode_get_prop_val(prov->nested_node, prop_info->guid, &v);
2353 if (FAILED(hr))
2354 return hr;
2355
2356 switch (prop_info->type)
2357 {
2358 case UIAutomationType_Element:
2359 {
2360 HUIANODE node;
2361
2363 if (FAILED(hr))
2364 return hr;
2365
2366 get_variant_for_node(node, ret_val);
2367 VariantClear(&v);
2368 break;
2369 }
2370
2371 default:
2372 *ret_val = v;
2373 break;
2374 }
2375
2376 return S_OK;
2377}
2378
2379static HRESULT WINAPI uia_nested_node_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts)
2380{
2382
2383 TRACE("%p, %p\n", iface, out_opts);
2384
2385 return get_prov_opts_from_node_provider(prov->nested_node, 0, out_opts);
2386}
2387
2388static HRESULT WINAPI uia_nested_node_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val)
2389{
2391
2392 TRACE("%p, %p\n", iface, out_val);
2393
2394 return get_has_parent_from_node_provider(prov->nested_node, 0, out_val);
2395}
2396
2397static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val)
2398{
2400 HUIANODE node;
2401 HRESULT hr;
2402 VARIANT v;
2403
2404 TRACE("%p, %d, %p\n", iface, nav_dir, out_val);
2405
2406 VariantInit(out_val);
2407 hr = get_navigate_from_node_provider(prov->nested_node, 0, nav_dir, &v);
2408 if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
2409 return hr;
2410
2412 if (FAILED(hr))
2413 return hr;
2414
2415 get_variant_for_node(node, out_val);
2416 VariantClear(&v);
2417
2418 return S_OK;
2419}
2420
2421static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
2422{
2424 HUIANODE node;
2425 HRESULT hr;
2426 VARIANT v;
2427
2428 TRACE("%p, %#lx, %p\n", iface, flags, out_val);
2429
2430 VariantInit(out_val);
2432 if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
2433 return hr;
2434
2436 {
2437 *out_val = v;
2438 return S_OK;
2439 }
2440
2442 if (FAILED(hr))
2443 return hr;
2444
2445 get_variant_for_node(node, out_val);
2446 VariantClear(&v);
2447
2448 return S_OK;
2449}
2450
2451static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
2452{
2454 struct uia_event *event = (struct uia_event *)huiaevent;
2455 IWineUiaEvent *remote_event = NULL;
2456 HRESULT hr;
2457
2458 TRACE("%p, %#Ix\n", iface, huiaevent);
2459
2460 hr = IWineUiaNode_attach_event(prov->nested_node, GetCurrentProcessId(), event->event_cookie, &remote_event);
2461 if (FAILED(hr) || !remote_event)
2462 return hr;
2463
2465 IWineUiaEvent_Release(remote_event);
2466
2467 return hr;
2468}
2469
2471 LONG obj_id, LONG child_id, IProxyProviderWinEventSink *sink)
2472{
2473 FIXME("%p, %#lx, #%lx, %#lx, %#lx, %p: stub\n", iface, win_event, hwnd, obj_id, child_id, sink);
2474 /* This should not be called. */
2475 assert(0);
2476 return E_FAIL;
2477}
2478
2480{
2482 HUIANODE node;
2483 HRESULT hr;
2484 VARIANT v;
2485
2486 TRACE("%p, %#lx, %p\n", iface, flags, ret_val);
2487
2488 VariantInit(ret_val);
2490 if (FAILED(hr) || V_VT(&v) == VT_EMPTY)
2491 return hr;
2492
2494 {
2495 *ret_val = v;
2496 return S_OK;
2497 }
2498
2500 if (FAILED(hr))
2501 return hr;
2502
2503 get_variant_for_node(node, ret_val);
2504 VariantClear(&v);
2505
2506 return S_OK;
2507}
2508
2509static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl = {
2521};
2522
2523static BOOL is_nested_node_provider(IWineUiaProvider *iface)
2524{
2525 if (iface->lpVtbl == &uia_nested_node_provider_vtbl)
2526 return TRUE;
2527
2528 return FALSE;
2529}
2530
2532 BOOL unwrap)
2533{
2534 IWineUiaProvider *provider_iface = NULL;
2535 struct uia_nested_node_provider *prov;
2536 IWineUiaNode *nested_node;
2537 int prov_opts, prov_type;
2538 DWORD git_cookie;
2539 HRESULT hr;
2540
2541 hr = ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&nested_node);
2542 if (FAILED(hr))
2543 {
2545 return hr;
2546 }
2547
2549 if (FAILED(hr))
2550 {
2551 WARN("Failed to get provider options for node %p with hr %#lx\n", nested_node, hr);
2552 IWineUiaNode_Release(nested_node);
2554 return hr;
2555 }
2556
2557 /* Nested nodes can only serve as override or main providers. */
2558 if (prov_opts & ProviderOptions_OverrideProvider)
2559 prov_type = PROV_TYPE_OVERRIDE;
2560 else
2561 prov_type = PROV_TYPE_MAIN;
2562
2563 if (node->prov[prov_type])
2564 {
2565 TRACE("Already have a provider of type %d for this node.\n", prov_type);
2566 IWineUiaNode_Release(nested_node);
2568 return S_OK;
2569 }
2570
2571 /*
2572 * If we're retrieving a node from an HWND that belongs to the same thread
2573 * as the client making the request, return a normal provider instead of a
2574 * nested node provider.
2575 */
2576 if (unwrap)
2577 {
2579 struct uia_provider *prov_data;
2580
2581 if (!node_data)
2582 {
2583 ERR("Failed to get uia_node structure from nested node\n");
2585 return E_FAIL;
2586 }
2587
2588 provider_iface = node_data->prov[get_node_provider_type_at_idx(node_data, 0)];
2589 git_cookie = 0;
2590
2591 IWineUiaProvider_AddRef(provider_iface);
2592 prov_data = impl_from_IWineUiaProvider(provider_iface);
2593 prov_data->refuse_hwnd_node_providers = FALSE;
2594 prov_data->return_nested_node = FALSE;
2595 prov_data->parent_check_ran = FALSE;
2596
2597 IWineUiaNode_Release(nested_node);
2599 }
2600 else
2601 {
2602 prov = calloc(1, sizeof(*prov));
2603 if (!prov)
2604 return E_OUTOFMEMORY;
2605
2607 prov->nested_node = nested_node;
2608 prov->ref = 1;
2609 provider_iface = &prov->IWineUiaProvider_iface;
2610
2611 /*
2612 * We need to use the GIT on all nested node providers so that our
2613 * IWineUiaNode proxy is used in the correct apartment.
2614 */
2616 &IID_IWineUiaProvider, &git_cookie);
2617 if (FAILED(hr))
2618 {
2619 IWineUiaProvider_Release(&prov->IWineUiaProvider_iface);
2620 return hr;
2621 }
2622
2623 if (!node->hwnd)
2624 {
2625 ULONG hwnd;
2626
2627 hr = IWineUiaNode_get_hwnd(nested_node, &hwnd);
2628 if (SUCCEEDED(hr))
2629 node->hwnd = UlongToHandle(hwnd);
2630 }
2631 }
2632
2633 node->prov[prov_type] = provider_iface;
2634 node->git_cookie[prov_type] = git_cookie;
2635 if (!node->prov_count)
2636 node->creator_prov_type = prov_type;
2637 node->prov_count++;
2638
2639 return S_OK;
2640}
2641
2642HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags)
2643{
2644 struct uia_node *node;
2645 HRESULT hr;
2646
2647 *huianode = NULL;
2648
2649 hr = create_uia_node(&node, node_flags);
2650 if (FAILED(hr))
2651 {
2653 return hr;
2654 }
2655
2658 if (FAILED(hr))
2659 {
2660 free(node);
2661 return hr;
2662 }
2663
2664 if (node->hwnd)
2665 {
2667 if (FAILED(hr))
2668 WARN("uia_get_providers_for_hwnd failed with hr %#lx\n", hr);
2669 }
2670
2672 if (FAILED(hr))
2673 {
2674 IWineUiaNode_Release(&node->IWineUiaNode_iface);
2675 return hr;
2676 }
2677
2678 *huianode = (void *)&node->IWineUiaNode_iface;
2679
2680 return hr;
2681}
2682
2684{
2685 IWineUiaNode *node;
2686
2687 if (lr && SUCCEEDED(ObjectFromLresult(lr, &IID_IWineUiaNode, 0, (void **)&node)))
2688 IWineUiaNode_Release(node);
2689}
2690
2691/*
2692 * UiaNodeFromHandle is expected to work even if the calling thread hasn't
2693 * initialized COM. We marshal our node on a separate thread that initializes
2694 * COM for this reason.
2695 */
2697{
2699
2701 return E_FAIL;
2702
2704 args.lr = SendMessageW(node->hwnd, WM_GETOBJECT, 0, UiaRootObjectId);
2706 {
2709 }
2710
2711 if (!args.lr)
2712 {
2714 return S_FALSE;
2715 }
2716
2719}
2720
2721HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags)
2722{
2723 struct uia_node *node;
2724 HRESULT hr;
2725
2726 if (!out_node)
2727 return E_INVALIDARG;
2728
2729 *out_node = NULL;
2730
2731 if (!IsWindow(hwnd))
2733
2734 hr = create_uia_node(&node, node_flags);
2735 if (FAILED(hr))
2736 return hr;
2737
2738 node->hwnd = hwnd;
2740 if (FAILED(hr))
2741 {
2742 free(node);
2743 return hr;
2744 }
2745
2747 if (FAILED(hr))
2748 {
2749 IWineUiaNode_Release(&node->IWineUiaNode_iface);
2750 return hr;
2751 }
2752
2753 *out_node = (void *)&node->IWineUiaNode_iface;
2754
2755 return S_OK;
2756}
2757
2758/***********************************************************************
2759 * UiaNodeFromHandle (uiautomationcore.@)
2760 */
2762{
2763 TRACE("(%p, %p)\n", hwnd, huianode);
2764
2765 return create_uia_node_from_hwnd(hwnd, huianode, 0);
2766}
2767
2768/***********************************************************************
2769 * UiaGetRootNode (uiautomationcore.@)
2770 */
2771HRESULT WINAPI UiaGetRootNode(HUIANODE *huianode)
2772{
2773 TRACE("(%p)\n", huianode);
2774
2775 return UiaNodeFromHandle(GetDesktopWindow(), huianode);
2776}
2777
2778/***********************************************************************
2779 * UiaHasServerSideProvider (uiautomationcore.@)
2780 */
2782{
2783 HUIANODE node = NULL;
2784 HRESULT hr;
2785
2786 TRACE("(%p)\n", hwnd);
2787
2790
2791 return SUCCEEDED(hr);
2792}
2793
2794static HRESULT get_focused_uia_node(HUIANODE in_node, HUIANODE *out_node)
2795{
2796 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)in_node);
2797 const BOOL desktop_node = (node->hwnd == GetDesktopWindow());
2798 HRESULT hr = S_OK;
2799 VARIANT v;
2800 int i;
2801
2802 *out_node = NULL;
2803 VariantInit(&v);
2804 for (i = 0; i < node->prov_count; i++)
2805 {
2806 /*
2807 * When getting focus from nodes other than the desktop, we ignore
2808 * both the node's creator provider and its HWND provider. This avoids
2809 * the problem of returning the same provider twice from GetFocus.
2810 */
2811 if (!desktop_node && ((i == node->creator_prov_idx) ||
2813 continue;
2814
2815 hr = get_focus_from_node_provider(&node->IWineUiaNode_iface, i, 0, &v);
2816 if (FAILED(hr))
2817 break;
2818
2819 if (V_VT(&v) != VT_EMPTY)
2820 {
2821 hr = UiaHUiaNodeFromVariant(&v, out_node);
2822 if (FAILED(hr))
2823 *out_node = NULL;
2824 break;
2825 }
2826 }
2827
2828 return hr;
2829}
2830
2831/***********************************************************************
2832 * UiaNodeFromFocus (uiautomationcore.@)
2833 */
2834HRESULT WINAPI UiaNodeFromFocus(struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct)
2835{
2836 HUIANODE node, node2;
2837 HRESULT hr;
2838
2839 TRACE("(%p, %p, %p)\n", cache_req, out_req, tree_struct);
2840
2841 if (!cache_req || !out_req || !tree_struct)
2842 return E_INVALIDARG;
2843
2844 *out_req = NULL;
2845 *tree_struct = NULL;
2846
2848 if (FAILED(hr))
2849 return hr;
2850
2851 while (1)
2852 {
2853 hr = get_focused_uia_node(node, &node2);
2854 if (FAILED(hr))
2855 goto exit;
2856
2857 if (!node2)
2858 break;
2859
2861 node = node2;
2862 }
2863
2864 hr = UiaGetUpdatedCache(node, cache_req, NormalizeState_View, NULL, out_req, tree_struct);
2865 if (FAILED(hr))
2866 WARN("UiaGetUpdatedCache failed with hr %#lx\n", hr);
2867exit:
2869
2870 return hr;
2871}
2872
2873/***********************************************************************
2874 * UiaNodeRelease (uiautomationcore.@)
2875 */
2876BOOL WINAPI UiaNodeRelease(HUIANODE huianode)
2877{
2878 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
2879
2880 TRACE("(%p)\n", huianode);
2881
2882 if (!node)
2883 return FALSE;
2884
2885 IWineUiaNode_Release(&node->IWineUiaNode_iface);
2886 return TRUE;
2887}
2888
2890 const struct uia_prop_info *prop_info, VARIANT *v)
2891{
2892 HRESULT hr = S_OK;
2893 int i;
2894
2895 VariantInit(v);
2896 for (i = 0; i < node->prov_count; i++)
2897 {
2898 hr = get_prop_val_from_node_provider(&node->IWineUiaNode_iface, prop_info, i, v);
2899 if (FAILED(hr) || V_VT(v) != VT_EMPTY)
2900 break;
2901 }
2902
2903 return hr;
2904}
2905
2906/***********************************************************************
2907 * UiaGetPropertyValue (uiautomationcore.@)
2908 */
2909HRESULT WINAPI UiaGetPropertyValue(HUIANODE huianode, PROPERTYID prop_id, VARIANT *out_val)
2910{
2911 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
2912 const struct uia_prop_info *prop_info;
2913 HRESULT hr;
2914 VARIANT v;
2915
2916 TRACE("(%p, %d, %p)\n", huianode, prop_id, out_val);
2917
2918 if (!node || !out_val)
2919 return E_INVALIDARG;
2920
2921 V_VT(out_val) = VT_UNKNOWN;
2923
2924 prop_info = uia_prop_info_from_id(prop_id);
2925 if (!prop_info)
2926 return E_INVALIDARG;
2927
2928 if (!prop_info->type)
2929 {
2930 FIXME("No type info for prop_id %d\n", prop_id);
2931 return E_NOTIMPL;
2932 }
2933
2934 switch (prop_id)
2935 {
2936 case UIA_RuntimeIdPropertyId:
2937 {
2938 SAFEARRAY *sa;
2939
2940 hr = UiaGetRuntimeId(huianode, &sa);
2941 if (SUCCEEDED(hr) && sa)
2942 {
2943 V_VT(out_val) = VT_I4 | VT_ARRAY;
2944 V_ARRAY(out_val) = sa;
2945 }
2946 return S_OK;
2947 }
2948
2949 case UIA_ProviderDescriptionPropertyId:
2951 if (SUCCEEDED(hr) && (V_VT(&v) == VT_BSTR))
2952 *out_val = v;
2953 return hr;
2954
2955 default:
2956 break;
2957 }
2958
2959 hr = get_prop_val_from_node(node, prop_info, &v);
2960 if (SUCCEEDED(hr) && V_VT(&v) != VT_EMPTY)
2961 {
2962 /*
2963 * ElementArray types come back as an array of pointers to prevent the
2964 * HUIANODEs from getting marshaled. We need to convert them to
2965 * VT_UNKNOWN here.
2966 */
2967 if (prop_info->type == UIAutomationType_ElementArray)
2968 {
2970 if (V_VT(&v) != VT_EMPTY)
2971 *out_val = v;
2972 }
2973 else
2974 *out_val = v;
2975 }
2976
2977 return hr;
2978}
2979
2984};
2985
2987{
2988 LONG i, idx, lbound, elems;
2989 SAFEARRAY *sa2, *ret;
2990 HRESULT hr;
2991 int val;
2992
2993 ret = sa2 = NULL;
2994 hr = get_safearray_bounds(sa, &lbound, &elems);
2995 if (FAILED(hr))
2996 goto exit;
2997
2998 /* elems includes the UiaAppendRuntimeId value, so we only add 2. */
2999 if (!(sa2 = SafeArrayCreateVector(VT_I4, 0, elems + 2)))
3000 goto exit;
3001
3003 if (FAILED(hr))
3004 goto exit;
3005
3008 else if (root_opts & ProviderOptions_OverrideProvider)
3010 else
3012
3013 idx = 2;
3014 hr = SafeArrayPutElement(sa2, &idx, &val);
3015 if (FAILED(hr))
3016 goto exit;
3017
3018 for (i = 0; i < (elems - 1); i++)
3019 {
3020 idx = (lbound + 1) + i;
3022 if (FAILED(hr))
3023 goto exit;
3024
3025 idx = (3 + i);
3026 hr = SafeArrayPutElement(sa2, &idx, &val);
3027 if (FAILED(hr))
3028 goto exit;
3029 }
3030
3031 ret = sa2;
3032
3033exit:
3034
3035 if (!ret)
3036 SafeArrayDestroy(sa2);
3037
3039 return ret;
3040}
3041
3042/***********************************************************************
3043 * UiaGetRuntimeId (uiautomationcore.@)
3044 */
3045HRESULT WINAPI UiaGetRuntimeId(HUIANODE huianode, SAFEARRAY **runtime_id)
3046{
3047 const struct uia_prop_info *prop_info = uia_prop_info_from_id(UIA_RuntimeIdPropertyId);
3048 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
3049 HRESULT hr;
3050
3051 TRACE("(%p, %p)\n", huianode, runtime_id);
3052
3053 if (!node || !runtime_id)
3054 return E_INVALIDARG;
3055
3056 *runtime_id = NULL;
3057
3058 /* Provide an HWND based runtime ID if the node has an HWND. */
3059 if (node->hwnd)
3060 {
3061 SAFEARRAY *sa;
3062
3063 if (!(sa = SafeArrayCreateVector(VT_I4, 0, 2)))
3064 return E_FAIL;
3065
3066 hr = write_runtime_id_base(sa, node->hwnd);
3067 if (FAILED(hr))
3068 {
3070 return hr;
3071 }
3072
3073 *runtime_id = sa;
3074 return S_OK;
3075 }
3076 else
3077 {
3078 VARIANT v;
3079
3080 hr = get_prop_val_from_node(node, prop_info, &v);
3081 if (FAILED(hr))
3082 {
3083 VariantClear(&v);
3084 return hr;
3085 }
3086
3087 if (V_VT(&v) == (VT_I4 | VT_ARRAY))
3088 *runtime_id = V_ARRAY(&v);
3089 }
3090
3091 return S_OK;
3092}
3093
3094/***********************************************************************
3095 * UiaHUiaNodeFromVariant (uiautomationcore.@)
3096 */
3097HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
3098{
3099 const VARTYPE expected_vt = sizeof(void *) == 8 ? VT_I8 : VT_I4;
3100
3101 TRACE("(%p, %p)\n", in_val, huianode);
3102
3103 if (!in_val || !huianode)
3104 return E_INVALIDARG;
3105
3106 *huianode = NULL;
3107 if ((V_VT(in_val) != expected_vt) && (V_VT(in_val) != VT_UNKNOWN))
3108 {
3109 WARN("Invalid vt %d\n", V_VT(in_val));
3110 return E_INVALIDARG;
3111 }
3112
3113 if (V_VT(in_val) == VT_UNKNOWN)
3114 {
3115 if (V_UNKNOWN(in_val))
3116 IUnknown_AddRef(V_UNKNOWN(in_val));
3117 *huianode = (HUIANODE)V_UNKNOWN(in_val);
3118 }
3119 else
3120 {
3121#ifdef _WIN64
3122 *huianode = (HUIANODE)V_I8(in_val);
3123#else
3124 *huianode = (HUIANODE)V_I4(in_val);
3125#endif
3126 }
3127
3128 return S_OK;
3129}
3130
3131#ifdef __REACTOS__
3133#else
3135#endif
3136{
3137 IRawElementProviderSimple *elprov = NULL;
3138 static BOOL fixme_once;
3139 SAFEARRAY *sa = NULL;
3140 HRESULT hr;
3141
3142 switch (prov_type)
3143 {
3144 case ProviderType_Proxy:
3145 {
3146 IAccessible *acc;
3147
3148 hr = AccessibleObjectFromWindow(hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
3149 if (FAILED(hr) || !acc)
3150 break;
3151
3152 hr = create_msaa_provider(acc, CHILDID_SELF, hwnd, TRUE, TRUE, &elprov);
3153 if (FAILED(hr))
3154 WARN("Failed to create MSAA proxy provider with hr %#lx\n", hr);
3155
3156 IAccessible_Release(acc);
3157 break;
3158 }
3159
3161 if (!fixme_once++)
3162 FIXME("Default ProviderType_NonClientArea provider unimplemented.\n");
3163 break;
3164
3166 hr = create_base_hwnd_provider(hwnd, &elprov);
3167 if (FAILED(hr))
3168 WARN("create_base_hwnd_provider failed with hr %#lx\n", hr);
3169 break;
3170
3171 default:
3172 break;
3173 }
3174
3175 if (elprov)
3176 {
3177 LONG idx = 0;
3178
3180 if (sa)
3181 SafeArrayPutElement(sa, &idx, (void *)elprov);
3182
3183 IRawElementProviderSimple_Release(elprov);
3184 }
3185
3186 return sa;
3187}
3188
3190
3191static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type,
3192 int node_prov_type)
3193{
3194 IRawElementProviderSimple *elprov;
3195 LONG lbound, elems;
3196 SAFEARRAY *sa;
3197 IUnknown *unk;
3198 VARTYPE vt;
3199 HRESULT hr;
3200
3201 if (node->ignore_clientside_hwnd_provs)
3202 return S_OK;
3203
3204 if (!(sa = uia_provider_callback(node->hwnd, prov_type)))
3205 return S_OK;
3206
3208 if (FAILED(hr) || (vt != VT_UNKNOWN))
3209 goto exit;
3210
3211 hr = get_safearray_bounds(sa, &lbound, &elems);
3212 if (FAILED(hr))
3213 goto exit;
3214
3215 /* Returned SAFEARRAY can only have 1 element. */
3216 if (elems != 1)
3217 {
3218 WARN("Invalid element count %ld for returned SAFEARRAY\n", elems);
3219 goto exit;
3220 }
3221
3222 hr = SafeArrayGetElement(sa, &lbound, &unk);
3223 if (FAILED(hr))
3224 goto exit;
3225
3226 hr = IUnknown_QueryInterface(unk, &IID_IRawElementProviderSimple, (void **)&elprov);
3227 IUnknown_Release(unk);
3228 if (FAILED(hr) || !elprov)
3229 {
3230 WARN("Failed to get IRawElementProviderSimple from returned SAFEARRAY.\n");
3231 hr = S_OK;
3232 goto exit;
3233 }
3234
3235 hr = create_wine_uia_provider(node, elprov, node_prov_type);
3236 IRawElementProviderSimple_Release(elprov);
3237
3238exit:
3239 if (FAILED(hr))
3240 WARN("Failed to get clientside provider, hr %#lx\n", hr);
3242 return hr;
3243}
3244
3246{
3247 static BOOL fixme_once;
3248 HRESULT hr;
3249
3251 if (FAILED(hr))
3252 return hr;
3253
3254 if (!node->prov[PROV_TYPE_MAIN])
3255 {
3257 if (FAILED(hr))
3258 return hr;
3259 }
3260
3261 if (!node->prov[PROV_TYPE_OVERRIDE] && !fixme_once++)
3262 FIXME("Override provider callback currently unimplemented.\n");
3263
3264 if (!node->prov[PROV_TYPE_NONCLIENT])
3265 {
3267 if (FAILED(hr))
3268 return hr;
3269 }
3270
3271 if (!node->prov[PROV_TYPE_HWND])
3272 {
3274 if (FAILED(hr))
3275 return hr;
3276 }
3277
3278 if (!node->prov_count)
3279 {
3281 return E_NOTIMPL;
3282 else
3283 return E_FAIL;
3284 }
3285
3286 return S_OK;
3287}
3288
3289/***********************************************************************
3290 * UiaRegisterProviderCallback (uiautomationcore.@)
3291 */
3293{
3294 TRACE("(%p)\n", callback);
3295
3296 if (callback)
3298 else
3300}
3301
3303{
3304 if (hr == S_FALSE)
3305 return FALSE;
3306 else
3307 return TRUE;
3308}
3309
3311{
3312 const struct uia_prop_info *prop_info = uia_prop_info_from_id(prop_cond->PropertyId);
3313 HRESULT hr;
3314 VARIANT v;
3315
3316 if (!prop_info)
3317 return E_INVALIDARG;
3318
3319 switch (prop_info->type)
3320 {
3321 case UIAutomationType_Bool:
3322 case UIAutomationType_IntArray:
3323 break;
3324
3325 default:
3326 FIXME("PropertyCondition comparison unimplemented for type %#x\n", prop_info->type);
3327 return E_NOTIMPL;
3328 }
3329
3330 hr = UiaGetPropertyValue(node, prop_info->prop_id, &v);
3331 if (FAILED(hr) || V_VT(&v) == VT_UNKNOWN)
3332 return S_FALSE;
3333
3334 if (V_VT(&v) == V_VT(&prop_cond->Value))
3335 {
3336 switch (prop_info->type)
3337 {
3338 case UIAutomationType_Bool:
3339 if (V_BOOL(&v) == V_BOOL(&prop_cond->Value))
3340 hr = S_OK;
3341 else
3342 hr = S_FALSE;
3343 break;
3344
3345 case UIAutomationType_IntArray:
3346 if (!uia_compare_safearrays(V_ARRAY(&v), V_ARRAY(&prop_cond->Value), prop_info->type))
3347 hr = S_OK;
3348 else
3349 hr = S_FALSE;
3350 break;
3351
3352 default:
3353 break;
3354 }
3355 }
3356 else
3357 hr = S_FALSE;
3358
3359 VariantClear(&v);
3360 return hr;
3361}
3362
3364{
3365 HRESULT hr;
3366
3367 switch (condition->ConditionType)
3368 {
3369 case ConditionType_True:
3370 return S_OK;
3371
3373 return S_FALSE;
3374
3375 case ConditionType_Not:
3376 {
3377 struct UiaNotCondition *not_cond = (struct UiaNotCondition *)condition;
3378
3379 hr = uia_condition_check(node, not_cond->pConditions);
3380 if (FAILED(hr))
3381 return hr;
3382
3384 return S_FALSE;
3385 else
3386 return S_OK;
3387 }
3388
3389 case ConditionType_And:
3390 case ConditionType_Or:
3391 {
3392 struct UiaAndOrCondition *and_or_cond = (struct UiaAndOrCondition *)condition;
3393 int i;
3394
3395 for (i = 0; i < and_or_cond->cConditions; i++)
3396 {
3397 hr = uia_condition_check(node, and_or_cond->ppConditions[i]);
3398 if (FAILED(hr))
3399 return hr;
3400
3401 if (condition->ConditionType == ConditionType_And && !uia_condition_matched(hr))
3402 return S_FALSE;
3403 else if (condition->ConditionType == ConditionType_Or && uia_condition_matched(hr))
3404 return S_OK;
3405 }
3406
3407 if (condition->ConditionType == ConditionType_Or)
3408 return S_FALSE;
3409 else
3410 return S_OK;
3411 }
3412
3415
3416 default:
3417 WARN("Invalid condition type %d\n", condition->ConditionType);
3418 return E_INVALIDARG;
3419 }
3420}
3421
3422static HRESULT uia_node_normalize(HUIANODE huianode, struct UiaCondition *cond, HUIANODE *normalized_node)
3423{
3424 struct uia_node *node = impl_from_IWineUiaNode((IWineUiaNode *)huianode);
3425 HRESULT hr;
3426
3427 *normalized_node = NULL;
3428 if (cond)
3429 {
3430 hr = uia_condition_check(huianode, cond);
3431 if (FAILED(hr))
3432 return hr;
3433
3434 /*
3435 * If our initial node doesn't match our normalization condition, need
3436 * to get the nearest ancestor that does.
3437 */
3439 return conditional_navigate_uia_node(node, NavigateDirection_Parent, cond, normalized_node);
3440 }
3441
3442 *normalized_node = huianode;
3443 IWineUiaNode_AddRef(&node->IWineUiaNode_iface);
3444 return S_OK;
3445}
3446
3447/***********************************************************************
3448 * UiaGetUpdatedCache (uiautomationcore.@)
3449 */
3450HRESULT WINAPI UiaGetUpdatedCache(HUIANODE huianode, struct UiaCacheRequest *cache_req, enum NormalizeState normalize_state,
3451 struct UiaCondition *normalize_cond, SAFEARRAY **out_req, BSTR *tree_struct)
3452{
3453 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
3454 struct UiaCondition *cond;
3455 SAFEARRAYBOUND sabound[2];
3456 HUIANODE ret_node;
3457 SAFEARRAY *sa;
3458 LONG idx[2];
3459 HRESULT hr;
3460 VARIANT v;
3461 int i;
3462
3463 TRACE("(%p, %p, %u, %p, %p, %p)\n", huianode, cache_req, normalize_state, normalize_cond, out_req, tree_struct);
3464
3465 if (!node || !out_req || !tree_struct || !cache_req)
3466 return E_INVALIDARG;
3467
3468 *tree_struct = NULL;
3469 *out_req = NULL;
3470
3471 if (cache_req->Scope != TreeScope_Element)
3472 {
3473 FIXME("Unsupported cache request scope %#x\n", cache_req->Scope);
3474 return E_NOTIMPL;
3475 }
3476
3477 if (cache_req->cPatterns && cache_req->pPatterns)
3478 FIXME("Pattern caching currently unimplemented\n");
3479
3480 if (cache_req->cProperties && cache_req->pProperties)
3481 {
3482 for (i = 0; i < cache_req->cProperties; i++)
3483 {
3484 if (!uia_prop_info_from_id(cache_req->pProperties[i]))
3485 return E_INVALIDARG;
3486 }
3487 }
3488
3489 switch (normalize_state)
3490 {
3492 cond = NULL;
3493 break;
3494
3496 cond = cache_req->pViewCondition;
3497 break;
3498
3500 cond = normalize_cond;
3501 break;
3502
3503 default:
3504 WARN("Invalid normalize_state %d\n", normalize_state);
3505 return E_INVALIDARG;
3506 }
3507
3508 hr = uia_node_normalize(huianode, cond, &ret_node);
3509 if (FAILED(hr))
3510 return hr;
3511
3512 if (!ret_node)
3513 {
3514 *tree_struct = SysAllocString(L"");
3515 return S_OK;
3516 }
3517
3518 sabound[0].cElements = 1;
3519 sabound[1].cElements = 1 + cache_req->cProperties;
3520 sabound[0].lLbound = sabound[1].lLbound = 0;
3521 if (!(sa = SafeArrayCreate(VT_VARIANT, 2, sabound)))
3522 {
3523 WARN("Failed to create safearray\n");
3524 hr = E_FAIL;
3525 goto exit;
3526 }
3527
3528 get_variant_for_node(ret_node, &v);
3529 idx[0] = idx[1] = 0;
3530
3532 if (FAILED(hr))
3533 goto exit;
3534
3535 idx[0] = 0;
3536 VariantClear(&v);
3537 for (i = 0; i < cache_req->cProperties; i++)
3538 {
3539 hr = UiaGetPropertyValue(ret_node, cache_req->pProperties[i], &v);
3540 /* Don't fail on unimplemented properties. */
3541 if (FAILED(hr) && hr != E_NOTIMPL)
3542 goto exit;
3543
3544 idx[1] = 1 + i;
3546 VariantClear(&v);
3547 if (FAILED(hr))
3548 goto exit;
3549 }
3550
3551 *out_req = sa;
3552 *tree_struct = SysAllocString(L"P)");
3553
3554exit:
3555 if (FAILED(hr))
3556 {
3558 UiaNodeRelease(ret_node);
3559 }
3560
3561 return hr;
3562}
3563
3564/***********************************************************************
3565 * UiaNavigate (uiautomationcore.@)
3566 */
3567HRESULT WINAPI UiaNavigate(HUIANODE huianode, enum NavigateDirection dir, struct UiaCondition *nav_condition,
3568 struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct)
3569{
3570 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
3571 HUIANODE node2 = NULL;
3572 HRESULT hr;
3573
3574 TRACE("(%p, %u, %p, %p, %p, %p)\n", huianode, dir, nav_condition, cache_req, out_req,
3575 tree_struct);
3576
3577 if (!node || !nav_condition || !cache_req || !out_req || !tree_struct)
3578 return E_INVALIDARG;
3579
3580 *out_req = NULL;
3581 *tree_struct = NULL;
3582
3583 hr = conditional_navigate_uia_node(node, dir, nav_condition, &node2);
3584 if (SUCCEEDED(hr) && node2)
3585 {
3586 hr = UiaGetUpdatedCache(node2, cache_req, NormalizeState_None, NULL, out_req, tree_struct);
3587 if (FAILED(hr))
3588 WARN("UiaGetUpdatedCache failed with hr %#lx\n", hr);
3589 UiaNodeRelease(node2);
3590 }
3591
3592 return hr;
3593}
3594
3595/* Combine multiple cache requests into a single SAFEARRAY. */
3596static HRESULT uia_cache_request_combine(SAFEARRAY **reqs, int reqs_count, SAFEARRAY *out_req)
3597{
3598 LONG idx[2], lbound[2], elems[2], cur_offset;
3599 int i, x, y;
3600 HRESULT hr;
3601 VARIANT v;
3602
3603 for (i = cur_offset = 0; i < reqs_count; i++)
3604 {
3605 if (!reqs[i])
3606 continue;
3607
3608 for (x = 0; x < 2; x++)
3609 {
3610 hr = get_safearray_dim_bounds(reqs[i], 1 + x, &lbound[x], &elems[x]);
3611 if (FAILED(hr))
3612 return hr;
3613 }
3614
3615 for (x = 0; x < elems[0]; x++)
3616 {
3617 for (y = 0; y < elems[1]; y++)
3618 {
3619 idx[0] = x + lbound[0];
3620 idx[1] = y + lbound[1];
3621 hr = SafeArrayGetElement(reqs[i], idx, &v);
3622 if (FAILED(hr))
3623 return hr;
3624
3625 idx[0] = x + cur_offset;
3626 idx[1] = y;
3627 hr = SafeArrayPutElement(out_req, idx, &v);
3628 if (FAILED(hr))
3629 return hr;
3630 }
3631 }
3632
3633 cur_offset += elems[0];
3634 }
3635
3636 return S_OK;
3637}
3638
3639/***********************************************************************
3640 * UiaFind (uiautomationcore.@)
3641 */
3642HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, struct UiaCacheRequest *cache_req,
3643 SAFEARRAY **out_req, SAFEARRAY **out_offsets, SAFEARRAY **out_tree_structs)
3644{
3645 struct UiaPropertyCondition prop_cond = { ConditionType_Property, UIA_RuntimeIdPropertyId };
3646 struct uia_node *node = unsafe_impl_from_IWineUiaNode((IWineUiaNode *)huianode);
3647 SAFEARRAY *runtime_id, *req, *offsets, *tree_structs, **tmp_reqs;
3648 struct UiaCondition *sibling_stop_cond;
3649 struct uia_node_array nodes = { 0 };
3650 LONG idx, lbound, elems, cur_offset;
3651 SAFEARRAYBOUND sabound[2];
3652 int i, cur_depth = 0;
3653 BSTR tree_struct;
3654 BOOL root_found;
3655 HRESULT hr;
3656
3657 TRACE("(%p, %p, %p, %p, %p, %p)\n", huianode, find_params, cache_req, out_req, out_offsets, out_tree_structs);
3658
3659 if (!node || !find_params || !cache_req || !out_req || !out_offsets || !out_tree_structs)
3660 return E_INVALIDARG;
3661
3662 *out_tree_structs = *out_offsets = *out_req = tree_structs = offsets = req = NULL;
3663 tmp_reqs = NULL;
3664
3665 /*
3666 * If the initial node has a runtime ID, we'll use it as a stop
3667 * condition.
3668 */
3669 hr = UiaGetRuntimeId(huianode, &runtime_id);
3670 if (SUCCEEDED(hr) && runtime_id)
3671 {
3672 V_VT(&prop_cond.Value) = VT_I4 | VT_ARRAY;
3673 V_ARRAY(&prop_cond.Value) = runtime_id;
3674 sibling_stop_cond = (struct UiaCondition *)&prop_cond;
3675 }
3676 else
3677 sibling_stop_cond = (struct UiaCondition *)&UiaFalseCondition;
3678
3679 if (find_params->ExcludeRoot)
3680 root_found = FALSE;
3681 else
3682 root_found = TRUE;
3683
3684 IWineUiaNode_AddRef(&node->IWineUiaNode_iface);
3685 hr = traverse_uia_node_tree(huianode, cache_req->pViewCondition, find_params->pFindCondition, sibling_stop_cond,
3686 cache_req->pViewCondition, TreeTraversalOptions_Default, TRUE, find_params->FindFirst, &root_found,
3687 find_params->MaxDepth, &cur_depth, &nodes);
3688 if (FAILED(hr) || !nodes.node_count)
3689 goto exit;
3690
3691 if (!(offsets = SafeArrayCreateVector(VT_I4, 0, nodes.node_count)))
3692 {
3693 hr = E_FAIL;
3694 goto exit;
3695 }
3696
3697 if (!(tree_structs = SafeArrayCreateVector(VT_BSTR, 0, nodes.node_count)))
3698 {
3699 hr = E_FAIL;
3700 goto exit;
3701 }
3702
3703 if (!(tmp_reqs = calloc(nodes.node_count, sizeof(*tmp_reqs))))
3704 {
3705 hr = E_OUTOFMEMORY;
3706 goto exit;
3707 }
3708
3709 /*
3710 * Get a count of how many total nodes we'll need to return, as well as
3711 * set the tree structure strings and cache request offsets for our final
3712 * combined SAFEARRAY.
3713 */
3714 for (i = cur_offset = 0; i < nodes.node_count; i++)
3715 {
3716 hr = UiaGetUpdatedCache(nodes.nodes[i], cache_req, NormalizeState_None, NULL, &tmp_reqs[i], &tree_struct);
3717 if (FAILED(hr))
3718 goto exit;
3719
3720 idx = i;
3721 hr = SafeArrayPutElement(tree_structs, &idx, tree_struct);
3722 SysFreeString(tree_struct);
3723 if (FAILED(hr))
3724 goto exit;
3725
3726 hr = SafeArrayPutElement(offsets, &idx, &cur_offset);
3727 if (FAILED(hr))
3728 goto exit;
3729
3730 if (!tmp_reqs[i])
3731 continue;
3732
3733 hr = get_safearray_dim_bounds(tmp_reqs[i], 1, &lbound, &elems);
3734 if (FAILED(hr))
3735 goto exit;
3736
3737 cur_offset += elems;
3738 }
3739
3740 if (nodes.node_count == 1)
3741 {
3742 req = tmp_reqs[0];
3743 free(tmp_reqs);
3744 tmp_reqs = NULL;
3745 }
3746 else
3747 {
3748 sabound[0].lLbound = sabound[1].lLbound = 0;
3749 sabound[0].cElements = cur_offset;
3750 sabound[1].cElements = 1 + cache_req->cProperties + cache_req->cPatterns;
3751 if (!(req = SafeArrayCreate(VT_VARIANT, 2, sabound)))
3752 {
3753 hr = E_FAIL;
3754 goto exit;
3755 }
3756
3757 hr = uia_cache_request_combine(tmp_reqs, nodes.node_count, req);
3758 if (FAILED(hr))
3759 goto exit;
3760 }
3761
3762 *out_tree_structs = tree_structs;
3763 *out_offsets = offsets;
3764 *out_req = req;
3765
3766exit:
3767 VariantClear(&prop_cond.Value);
3768 clear_node_array(&nodes);
3769
3770 if (tmp_reqs)
3771 {
3772 for (i = 0; i < nodes.node_count; i++)
3773 SafeArrayDestroy(tmp_reqs[i]);
3774 free(tmp_reqs);
3775 }
3776
3777 if (FAILED(hr))
3778 {
3779 SafeArrayDestroy(tree_structs);
3781 SafeArrayDestroy(req);
3782 }
3783
3784 return hr;
3785}
3786
3787/***********************************************************************
3788 * UiaEventRemoveWindow (uiautomationcore.@)
3789 */
3791{
3792 FIXME("(%p, %p): stub\n", huiaevent, hwnd);
3793 return E_NOTIMPL;
3794}
@ lparam
Definition: SystemMenu.c:31
@ wparam
Definition: SystemMenu.c:30
static struct sockaddr_in sa
Definition: adnsresfilter.c:69
unsigned int dir
Definition: maze.c:112
#define InterlockedIncrement
Definition: armddk.h:53
#define InterlockedDecrement
Definition: armddk.h:52
#define msg(x)
Definition: auth_time.c:54
#define WINE_DEFAULT_DEBUG_CHANNEL(t)
Definition: precomp.h:23
#define ARRAY_SIZE(A)
Definition: main.h:20
static int list_empty(struct list_entry *head)
Definition: list.h:58
static void list_init(struct list_entry *head)
Definition: list.h:51
#define FIXME(fmt,...)
Definition: precomp.h:53
#define WARN(fmt,...)
Definition: precomp.h:61
#define ERR(fmt,...)
Definition: precomp.h:57
#define UlongToHandle(ul)
Definition: basetsd.h:91
#define HandleToUlong(h)
Definition: basetsd.h:73
const GUID IID_IUnknown
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define E_INVALIDARG
Definition: ddrawi.h:101
#define E_NOTIMPL
Definition: ddrawi.h:99
#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 CoIncrementMTAUsage(CO_MTA_USAGE_COOKIE *cookie)
Definition: combase.c:2907
HRESULT WINAPI CoDecrementMTAUsage(CO_MTA_USAGE_COOKIE cookie)
Definition: combase.c:2917
static void unwrap(TOOLBAR_INFO *info)
Definition: toolbar.c:5274
#define CloseHandle
Definition: compat.h:739
#define SetLastError(x)
Definition: compat.h:752
#define FreeLibrary(x)
Definition: compat.h:748
OLECHAR * BSTR
Definition: compat.h:2293
unsigned short VARTYPE
Definition: compat.h:2254
#define CALLBACK
Definition: compat.h:35
@ VT_BSTR
Definition: compat.h:2303
@ VT_UINT_PTR
Definition: compat.h:2328
@ VT_UNKNOWN
Definition: compat.h:2308
@ VT_ARRAY
Definition: compat.h:2341
@ VT_R8
Definition: compat.h:2300
@ VT_VARIANT
Definition: compat.h:2307
@ VT_I8
Definition: compat.h:2314
@ VT_I4
Definition: compat.h:2298
@ VT_BOOL
Definition: compat.h:2306
@ VT_EMPTY
Definition: compat.h:2295
#define lstrlenW
Definition: compat.h:750
BOOL WINAPI GetModuleHandleExW(IN DWORD dwFlags, IN LPCWSTR lpwModuleName OPTIONAL, OUT HMODULE *phModule)
Definition: loader.c:866
VOID WINAPI FreeLibraryAndExitThread(HMODULE hLibModule, DWORD dwExitCode)
Definition: loader.c:507
HANDLE WINAPI DECLSPEC_HOTPATCH CreateThread(IN LPSECURITY_ATTRIBUTES lpThreadAttributes, IN DWORD dwStackSize, IN LPTHREAD_START_ROUTINE lpStartAddress, IN LPVOID lpParameter, IN DWORD dwCreationFlags, OUT LPDWORD lpThreadId)
Definition: thread.c:137
UINT(* handler)(MSIPACKAGE *)
Definition: action.c:7512
static REFPROPVARIANT PROPVAR_CHANGE_FLAGS VARTYPE vt
Definition: suminfo.c:91
#define assert(_expr)
Definition: assert.h:32
HRESULT WINAPI AccessibleObjectFromWindow(HWND hwnd, DWORD dwObjectID, REFIID riid, void **ppvObject)
Definition: main.c:349
HRESULT WINAPI ObjectFromLresult(LRESULT result, REFIID riid, WPARAM wParam, void **ppObject)
Definition: main.c:177
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
SAFEARRAY *WINAPI SafeArrayCreateVector(VARTYPE vt, LONG lLbound, ULONG cElements)
Definition: safearray.c:677
HRESULT WINAPI SafeArrayGetLBound(SAFEARRAY *psa, UINT nDim, LONG *plLbound)
Definition: safearray.c:1066
HRESULT WINAPI SafeArrayDestroy(SAFEARRAY *psa)
Definition: safearray.c:1347
SAFEARRAY *WINAPI SafeArrayCreate(VARTYPE vt, UINT cDims, SAFEARRAYBOUND *rgsabound)
Definition: safearray.c:600
HRESULT WINAPI SafeArrayGetVartype(SAFEARRAY *psa, VARTYPE *pvt)
Definition: safearray.c:1534
HRESULT WINAPI SafeArrayPutElement(SAFEARRAY *psa, LONG *rgIndices, void *pvData)
Definition: safearray.c:864
return ret
Definition: mutex.c:146
#define L(x)
Definition: resources.c:13
r parent
Definition: btrfs.c:3010
#define INFINITE
Definition: serial.h:102
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
static const FxOffsetAndName offsets[]
GLint GLint GLsizei GLsizei GLsizei depth
Definition: gl.h:1546
GLint GLint GLint GLint GLint x
Definition: gl.h:1548
const GLdouble * v
Definition: gl.h:2040
GLint GLint GLint GLint GLint GLint y
Definition: gl.h:1548
struct _cl_event * event
Definition: glext.h:7739
GLenum condition
Definition: glext.h:9255
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:7751
GLuint in
Definition: glext.h:9616
GLbitfield flags
Definition: glext.h:7161
GLsizei GLenum GLboolean sink
Definition: glext.h:5672
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
REFIID LPVOID * ppv
Definition: atlbase.h:39
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define debugstr_guid
Definition: kernel32.h:35
LPWSTR WINAPI lstrcatW(LPWSTR lpString1, LPCWSTR lpString2)
Definition: lstring.c:274
LONG_PTR LPARAM
Definition: minwindef.h:175
LONG_PTR LRESULT
Definition: minwindef.h:176
UINT_PTR WPARAM
Definition: minwindef.h:174
HANDLE events[2]
Definition: event.c:4
static IPrintDialogCallback callback
Definition: printdlg.c:326
static HMODULE hmodule
Definition: rasapi.c:29
__int3264 LONG_PTR
Definition: mstsclib_h.h:276
unsigned int UINT
Definition: ndis.h:50
BSTR WINAPI SysAllocString(LPCOLESTR str)
Definition: oleaut.c:238
UINT WINAPI SysStringLen(BSTR str)
Definition: oleaut.c:196
void WINAPI DECLSPEC_HOTPATCH SysFreeString(BSTR str)
Definition: oleaut.c:271
int WINAPI SysReAllocStringLen(BSTR *old, const OLECHAR *str, unsigned int len)
Definition: oleaut.c:383
BSTR WINAPI SysAllocStringLen(const OLECHAR *str, unsigned int len)
Definition: oleaut.c:339
#define V_I8(A)
Definition: oleauto.h:249
#define V_BOOL(A)
Definition: oleauto.h:224
#define V_ARRAY(A)
Definition: oleauto.h:222
#define V_UNKNOWN(A)
Definition: oleauto.h:281
#define V_VT(A)
Definition: oleauto.h:211
#define V_BSTR(A)
Definition: oleauto.h:226
#define V_I4(A)
Definition: oleauto.h:247
long LONG
Definition: pedump.c:60
#define IsEqualIID(riid1, riid2)
Definition: guiddef.h:95
#define REFIID
Definition: guiddef.h:118
#define calloc
Definition: rosglue.h:14
#define exit(n)
Definition: config.h:202
#define memset(x, y, z)
Definition: compat.h:39
#define TRACE(s)
Definition: solgame.cpp:4
& rect
Definition: startmenu.cpp:1413
struct UiaCondition ** ppConditions
enum TreeScope Scope
struct UiaCondition * pViewCondition
PROPERTYID * pProperties
enum ConditionType ConditionType
struct UiaCondition * pFindCondition
struct UiaCondition * pConditions
Definition: match.c:390
Definition: send.c:48
CO_MTA_USAGE_COOKIE mta_cookie
Definition: uia_client.c:2129
LONG event_cookie
Definition: uia_private.h:138
LONG proc_id
Definition: uia_private.h:155
IWineUiaProvider IWineUiaProvider_iface
Definition: uia_client.c:2288
IWineUiaNode * nested_node
Definition: uia_client.c:2291
HUIANODE * nodes
Definition: uia_client.c:28
SIZE_T node_arr_size
Definition: uia_client.c:30
int creator_prov_idx
Definition: uia_private.h:72
LONG ref
Definition: uia_private.h:66
BOOL nested_node
Definition: uia_private.h:76
IWineUiaProvider * prov[PROV_TYPE_COUNT]
Definition: uia_private.h:68
DWORD git_cookie[PROV_TYPE_COUNT]
Definition: uia_private.h:69
IWineUiaNode IWineUiaNode_iface
Definition: uia_private.h:65
int prov_count
Definition: uia_private.h:70
int parent_link_idx
Definition: uia_private.h:71
int creator_prov_type
Definition: uia_private.h:78
HWND hwnd
Definition: uia_private.h:74
const GUID * pattern_iid
Definition: uia_classes.idl:41
const GUID * guid
Definition: uia_classes.idl:25
IRawElementProviderSimple * elprov
Definition: uia_private.h:96
BOOL return_nested_node
Definition: uia_private.h:98
BOOL refuse_hwnd_node_providers
Definition: uia_private.h:97
IWineUiaProvider IWineUiaProvider_iface
Definition: uia_private.h:93
BOOL parent_check_ran
Definition: uia_private.h:99
DWORD WINAPI WaitForMultipleObjects(IN DWORD nCount, IN CONST HANDLE *lpHandles, IN BOOL bWaitAll, IN DWORD dwMilliseconds)
Definition: synch.c:151
HANDLE WINAPI DECLSPEC_HOTPATCH CreateEventW(IN LPSECURITY_ATTRIBUTES lpEventAttributes OPTIONAL, IN BOOL bManualReset, IN BOOL bInitialState, IN LPCWSTR lpName OPTIONAL)
Definition: synch.c:587
BOOL WINAPI DECLSPEC_HOTPATCH SetEvent(IN HANDLE hEvent)
Definition: synch.c:669
#define GWLP_WNDPROC
Definition: treelist.c:66
#define DWORD_PTR
Definition: treelist.c:76
TW_UINT32 TW_UINT16 TW_UINT16 MSG
Definition: twain.h:1829
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
static HRESULT uia_node_normalize(HUIANODE huianode, struct UiaCondition *cond, HUIANODE *normalized_node)
Definition: uia_client.c:3422
static UiaProviderCallback * uia_provider_callback
Definition: uia_client.c:3189
static HRESULT WINAPI uia_nested_node_provider_get_prop_val(IWineUiaProvider *iface, const struct uia_prop_info *prop_info, VARIANT *ret_val)
Definition: uia_client.c:2336
static HRESULT get_prop_val_from_node(struct uia_node *node, const struct uia_prop_info *prop_info, VARIANT *v)
Definition: uia_client.c:2889
static HRESULT create_wine_uia_nested_node_provider(struct uia_node *node, LRESULT lr, BOOL unwrap)
Definition: uia_client.c:2531
static HRESULT get_navigate_from_node_provider(IWineUiaNode *node, int idx, int nav_dir, VARIANT *ret_val)
Definition: uia_client.c:334
static BOOL node_creator_is_parent_link(struct uia_node *node)
Definition: uia_client.c:800
static ULONG WINAPI uia_nested_node_provider_Release(IWineUiaProvider *iface)
Definition: uia_client.c:2320
static BOOL is_nested_node_provider(IWineUiaProvider *iface)
Definition: uia_client.c:2523
static const IWineUiaProviderVtbl uia_provider_vtbl
Definition: uia_client.c:2013
static HWND get_hwnd_from_provider(IRawElementProviderSimple *elprov)
Definition: uia_client.c:172
int get_node_provider_type_at_idx(struct uia_node *node, int idx)
Definition: uia_client.c:266
HRESULT uia_condition_check(HUIANODE node, struct UiaCondition *condition)
Definition: uia_client.c:3363
static const IWineUiaNodeVtbl uia_node_vtbl
Definition: uia_client.c:613
HRESULT WINAPI UiaGetRuntimeId(HUIANODE huianode, SAFEARRAY **runtime_id)
Definition: uia_client.c:3045
HRESULT WINAPI UiaNodeFromProvider(IRawElementProviderSimple *elprov, HUIANODE *huianode)
Definition: uia_client.c:2114
HRESULT WINAPI UiaGetUpdatedCache(HUIANODE huianode, struct UiaCacheRequest *cache_req, enum NormalizeState normalize_state, struct UiaCondition *normalize_cond, SAFEARRAY **out_req, BSTR *tree_struct)
Definition: uia_client.c:3450
HRESULT WINAPI UiaFind(HUIANODE huianode, struct UiaFindParams *find_params, struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, SAFEARRAY **out_offsets, SAFEARRAY **out_tree_structs)
Definition: uia_client.c:3642
static HRESULT WINAPI uia_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
Definition: uia_client.c:1839
static void uia_stop_client_thread(void)
Definition: uia_client.c:2267
static struct uia_client_thread client_thread
Definition: uia_client.c:2140
static HRESULT WINAPI uia_provider_QueryInterface(IWineUiaProvider *iface, REFIID riid, void **ppv)
Definition: uia_client.c:1356
static HRESULT WINAPI uia_nested_node_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
Definition: uia_client.c:2479
static HRESULT get_sibling_from_node_provider(struct uia_node *node, int prov_idx, int nav_dir, VARIANT *out_node)
Definition: uia_client.c:808
static IRawElementProviderSimple * get_provider_hwnd_fragment_root(IRawElementProviderSimple *elprov, HWND *hwnd)
Definition: uia_client.c:203
static HRESULT conditional_navigate_uia_node(struct uia_node *node, int nav_dir, struct UiaCondition *cond, HUIANODE *out_node)
Definition: uia_client.c:1002
static HRESULT get_node_provider_description_string(struct uia_node *node, VARIANT *out_desc)
Definition: uia_client.c:1269
fragment_root_prov_type_ids
Definition: uia_client.c:2980
@ FRAGMENT_ROOT_NONCLIENT_TYPE_ID
Definition: uia_client.c:2981
@ FRAGMENT_ROOT_OVERRIDE_TYPE_ID
Definition: uia_client.c:2983
@ FRAGMENT_ROOT_MAIN_TYPE_ID
Definition: uia_client.c:2982
static HRESULT bstrcat_realloc(BSTR *bstr, const WCHAR *cat_str)
Definition: uia_client.c:1249
static void clear_uia_node_ptr_safearray(SAFEARRAY *sa, LONG elems)
Definition: uia_client.c:61
static HRESULT get_has_parent_from_node_provider(IWineUiaNode *node, int idx, BOOL *out_val)
Definition: uia_client.c:318
HRESULT WINAPI UiaNodeFromFocus(struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct)
Definition: uia_client.c:2834
static const WCHAR * prov_desc_type_str[]
Definition: uia_client.c:1262
static HRESULT WINAPI uia_nested_node_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val)
Definition: uia_client.c:2397
HRESULT WINAPI UiaGetPropertyValue(HUIANODE huianode, PROPERTYID prop_id, VARIANT *out_val)
Definition: uia_client.c:2909
static const struct UiaCondition UiaFalseCondition
Definition: uia_client.c:25
static const IWineUiaProviderVtbl uia_nested_node_provider_vtbl
Definition: uia_client.c:2509
static HRESULT uia_get_provider_from_hwnd(struct uia_node *node)
Definition: uia_client.c:2696
static HRESULT get_prop_val_from_node_provider(IWineUiaNode *node, const struct uia_prop_info *prop_info, int idx, VARIANT *out_val)
Definition: uia_client.c:285
BOOL WINAPI UiaNodeRelease(HUIANODE huianode)
Definition: uia_client.c:2876
static HRESULT WINAPI uia_nested_node_provider_respond_to_win_event(IWineUiaProvider *iface, DWORD win_event, ULONG hwnd, LONG obj_id, LONG child_id, IProxyProviderWinEventSink *sink)
Definition: uia_client.c:2470
static CRITICAL_SECTION_DEBUG client_thread_cs_debug
Definition: uia_client.c:2142
static HRESULT WINAPI uia_nested_node_provider_QueryInterface(IWineUiaProvider *iface, REFIID riid, void **ppv)
Definition: uia_client.c:2299
static HRESULT WINAPI uia_nested_node_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
Definition: uia_client.c:2451
static HRESULT uia_provider_get_pattern_prop_val(struct uia_provider *prov, const struct uia_prop_info *prop_info, VARIANT *ret_val)
Definition: uia_client.c:1673
HRESULT WINAPI UiaNavigate(HUIANODE huianode, enum NavigateDirection dir, struct UiaCondition *nav_condition, struct UiaCacheRequest *cache_req, SAFEARRAY **out_req, BSTR *tree_struct)
Definition: uia_client.c:3567
static HRESULT WINAPI uia_node_get_prop_val(IWineUiaNode *iface, const GUID *prop_guid, VARIANT *ret_val)
Definition: uia_client.c:505
static ULONG WINAPI uia_node_AddRef(IWineUiaNode *iface)
Definition: uia_client.c:428
HRESULT attach_event_to_uia_node(HUIANODE node, struct uia_event *event)
Definition: uia_client.c:1337
HRESULT WINAPI UiaGetRootNode(HUIANODE *huianode)
Definition: uia_client.c:2771
static HRESULT WINAPI uia_node_QueryInterface(IWineUiaNode *iface, REFIID riid, void **ppv)
Definition: uia_client.c:416
HRESULT respond_to_win_event_on_node_provider(IWineUiaNode *node, int idx, DWORD win_event, HWND hwnd, LONG obj_id, LONG child_id, IProxyProviderWinEventSink *sink)
Definition: uia_client.c:381
static HRESULT uia_cache_request_combine(SAFEARRAY **reqs, int reqs_count, SAFEARRAY *out_req)
Definition: uia_client.c:3596
static ULONG WINAPI uia_nested_node_provider_AddRef(IWineUiaProvider *iface)
Definition: uia_client.c:2311
static HRESULT add_node_to_node_array(struct uia_node_array *out_nodes, HUIANODE node)
Definition: uia_client.c:48
static DWORD WINAPI uia_client_thread_proc(void *arg)
Definition: uia_client.c:2171
HRESULT clone_uia_node(HUIANODE in_node, HUIANODE *out_node)
Definition: uia_client.c:738
static void create_uia_node_safearray(VARIANT *in, VARIANT *out)
Definition: uia_client.c:76
HRESULT WINAPI UiaEventRemoveWindow(HUIAEVENT huiaevent, HWND hwnd)
Definition: uia_client.c:3790
static HRESULT WINAPI uia_provider_create_node_from_prov(IWineUiaProvider *iface, LONG flags, VARIANT *ret_val)
Definition: uia_client.c:1993
static HRESULT create_uia_node(struct uia_node **out_node, int node_flags)
Definition: uia_client.c:632
HRESULT create_uia_node_from_hwnd(HWND hwnd, HUIANODE *out_node, int node_flags)
Definition: uia_client.c:2721
HRESULT WINAPI UiaHUiaNodeFromVariant(VARIANT *in_val, HUIANODE *huianode)
Definition: uia_client.c:3097
static SAFEARRAY * append_uia_runtime_id(SAFEARRAY *sa, HWND hwnd, enum ProviderOptions root_opts)
Definition: uia_client.c:2986
static ULONG WINAPI uia_provider_AddRef(IWineUiaProvider *iface)
Definition: uia_client.c:1368
static HRESULT traverse_uia_node_tree_siblings(HUIANODE huianode, struct UiaCondition *ascending_stop_cond, int dir, BOOL at_root_level, HUIANODE *out_node)
Definition: uia_client.c:1092
static HRESULT WINAPI uia_node_disconnect(IWineUiaNode *iface)
Definition: uia_client.c:532
#define WM_UIA_CLIENT_THREAD_STOP
Definition: uia_client.c:2151
static HRESULT attach_event_to_node_provider(IWineUiaNode *node, int idx, HUIAEVENT huiaevent)
Definition: uia_client.c:366
static HRESULT WINAPI uia_provider_attach_event(IWineUiaProvider *iface, LONG_PTR huiaevent)
Definition: uia_client.c:1874
static HRESULT uia_provider_get_special_prop_val(struct uia_provider *prov, const struct uia_prop_info *prop_info, VARIANT *ret_val)
Definition: uia_client.c:1535
static HRESULT uia_property_condition_check(HUIANODE node, struct UiaPropertyCondition *prop_cond)
Definition: uia_client.c:3310
static HRESULT WINAPI uia_node_attach_event(IWineUiaNode *iface, LONG proc_id, LONG event_cookie, IWineUiaEvent **ret_event)
Definition: uia_client.c:574
static HRESULT WINAPI uia_provider_navigate(IWineUiaProvider *iface, int nav_dir, VARIANT *out_val)
Definition: uia_client.c:1807
static HRESULT WINAPI uia_nested_node_provider_get_focus(IWineUiaProvider *iface, LONG flags, VARIANT *out_val)
Definition: uia_client.c:2421
static HRESULT create_wine_uia_provider(struct uia_node *node, IRawElementProviderSimple *elprov, int prov_type)
Definition: uia_client.c:2027
static ULONG WINAPI uia_provider_Release(IWineUiaProvider *iface)
Definition: uia_client.c:1378
static SAFEARRAY WINAPI * default_uia_provider_callback(HWND hwnd, enum ProviderType prov_type)
Definition: uia_client.c:3134
static HRESULT WINAPI uia_nested_node_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val)
Definition: uia_client.c:2388
void WINAPI UiaRegisterProviderCallback(UiaProviderCallback *callback)
Definition: uia_client.c:3292
static HRESULT WINAPI uia_node_get_hwnd(IWineUiaNode *iface, ULONG *out_hwnd)
Definition: uia_client.c:563
HRESULT navigate_uia_node(struct uia_node *node, int nav_dir, HUIANODE *out_node)
Definition: uia_client.c:914
static HRESULT WINAPI uia_provider_respond_to_win_event(IWineUiaProvider *iface, DWORD win_event, ULONG hwnd, LONG obj_id, LONG child_id, IProxyProviderWinEventSink *sink)
Definition: uia_client.c:1976
static struct uia_node * unsafe_impl_from_IWineUiaNode(IWineUiaNode *iface)
Definition: uia_client.c:624
HRESULT WINAPI UiaNodeFromHandle(HWND hwnd, HUIANODE *huianode)
Definition: uia_client.c:2761
static HRESULT get_variant_for_elprov_node(IRawElementProviderSimple *elprov, BOOL out_nested, BOOL refuse_hwnd_providers, VARIANT *v)
Definition: uia_client.c:1393
static HRESULT uia_get_providers_for_hwnd(struct uia_node *node)
Definition: uia_client.c:3245
HRESULT uia_node_from_lresult(LRESULT lr, HUIANODE *huianode, int node_flags)
Definition: uia_client.c:2642
static HRESULT WINAPI uia_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts)
Definition: uia_client.c:1759
static HRESULT get_focused_uia_node(HUIANODE in_node, HUIANODE *out_node)
Definition: uia_client.c:2794
static HRESULT WINAPI uia_nested_node_provider_get_prov_opts(IWineUiaProvider *iface, int *out_opts)
Definition: uia_client.c:2379
static HRESULT uia_provider_get_elem_prop_val(struct uia_provider *prov, const struct uia_prop_info *prop_info, VARIANT *ret_val)
Definition: uia_client.c:1422
HRESULT create_node_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
Definition: uia_client.c:397
static struct uia_nested_node_provider * impl_from_nested_node_IWineUiaProvider(IWineUiaProvider *iface)
Definition: uia_client.c:2294
static HRESULT get_prov_opts_from_node_provider(IWineUiaNode *node, int idx, int *out_opts)
Definition: uia_client.c:302
static void clear_node_array(struct uia_node_array *nodes)
Definition: uia_client.c:33
static HRESULT WINAPI uia_provider_has_parent(IWineUiaProvider *iface, BOOL *out_val)
Definition: uia_client.c:1775
static HRESULT get_child_for_node(struct uia_node *node, int start_prov_idx, int nav_dir, VARIANT *out_node)
Definition: uia_client.c:856
void uia_node_lresult_release(LRESULT lr)
Definition: uia_client.c:2683
HRESULT create_uia_node_from_elprov(IRawElementProviderSimple *elprov, HUIANODE *out_node, BOOL get_hwnd_providers, int node_flags)
Definition: uia_client.c:2049
static HRESULT prepare_uia_node(struct uia_node *node)
Definition: uia_client.c:656
static HRESULT WINAPI uia_node_get_provider(IWineUiaNode *iface, int idx, IWineUiaProvider **out_prov)
Definition: uia_client.c:470
static HRESULT traverse_uia_node_tree(HUIANODE huianode, struct UiaCondition *view_cond, struct UiaCondition *search_cond, struct UiaCondition *pre_sibling_nav_stop_cond, struct UiaCondition *ascending_stop_cond, int traversal_opts, BOOL at_root_level, BOOL find_first, BOOL *root_found, int max_depth, int *cur_depth, struct uia_node_array *out_nodes)
Definition: uia_client.c:1150
static HRESULT uia_get_clientside_provider(struct uia_node *node, int prov_type, int node_prov_type)
Definition: uia_client.c:3191
static BOOL uia_start_client_thread(void)
Definition: uia_client.c:2204
static void uia_node_ptr_to_unk_safearray(VARIANT *in)
Definition: uia_client.c:126
static LRESULT CALLBACK uia_client_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
Definition: uia_client.c:2153
#define WM_UIA_CLIENT_GET_NODE_PROV
Definition: uia_client.c:2150
static CRITICAL_SECTION client_thread_cs
Definition: uia_client.c:2141
static ULONG WINAPI uia_node_Release(IWineUiaNode *iface)
Definition: uia_client.c:437
HRESULT get_focus_from_node_provider(IWineUiaNode *node, int idx, LONG flags, VARIANT *ret_val)
Definition: uia_client.c:350
static HRESULT WINAPI uia_provider_get_prop_val(IWineUiaProvider *iface, const struct uia_prop_info *prop_info, VARIANT *ret_val)
Definition: uia_client.c:1733
BOOL uia_condition_matched(HRESULT hr)
Definition: uia_client.c:3302
BOOL WINAPI UiaHasServerSideProvider(HWND hwnd)
Definition: uia_client.c:2781
HRESULT uia_event_add_provider_event_adviser(IRawElementProviderAdviseEvents *advise_events, struct uia_event *event)
Definition: uia_event.c:1385
HRESULT create_serverside_uia_event(struct uia_event **out_event, LONG process_id, LONG event_cookie)
Definition: uia_event.c:1234
HRESULT uia_event_add_win_event_hwnd(struct uia_event *event, HWND hwnd)
Definition: uia_event.c:83
HRESULT uia_event_add_serverside_event_adviser(IWineUiaEvent *serverside_event, struct uia_event *event)
Definition: uia_event.c:1519
int WINAPI UiaLookupId(enum AutomationIdentifierType type, const GUID *guid)
Definition: uia_ids.c:627
const struct uia_pattern_info * uia_pattern_info_from_id(PATTERNID pattern_id)
Definition: uia_ids.c:540
const struct uia_prop_info * uia_prop_info_from_id(PROPERTYID prop_id)
Definition: uia_ids.c:332
HMODULE huia_module
Definition: uia_main.c:29
HRESULT WINAPI UiaGetReservedNotSupportedValue(IUnknown **value)
Definition: uia_main.c:289
static struct uia_provider * impl_from_IWineUiaProvider(IWineUiaProvider *iface)
Definition: uia_private.h:104
HRESULT register_interface_in_git(IUnknown *iface, REFIID riid, DWORD *ret_cookie)
Definition: uia_utils.c:40
HRESULT create_msaa_provider(IAccessible *acc, LONG child_id, HWND hwnd, BOOL root_acc_known, BOOL is_root_acc, IRawElementProviderSimple **elprov)
HRESULT get_interface_in_git(REFIID riid, DWORD git_cookie, IUnknown **ret_iface)
Definition: uia_utils.c:79
static void get_variant_for_node(HUIANODE node, VARIANT *v)
Definition: uia_private.h:175
@ NODE_FLAG_IGNORE_CLIENTSIDE_HWND_PROVS
Definition: uia_private.h:59
@ NODE_FLAG_IGNORE_COM_THREADING
Definition: uia_private.h:61
@ NODE_FLAG_NO_PREPARE
Definition: uia_private.h:60
void uia_stop_provider_thread(void)
@ PROV_TYPE_OVERRIDE
Definition: uia_private.h:51
@ PROV_TYPE_MAIN
Definition: uia_private.h:52
@ PROV_TYPE_HWND
Definition: uia_private.h:54
@ PROV_TYPE_NONCLIENT
Definition: uia_private.h:53
@ PROV_TYPE_COUNT
Definition: uia_private.h:55
LRESULT uia_lresult_from_node(HUIANODE huianode)
HRESULT get_safearray_bounds(SAFEARRAY *sa, LONG *lbound, LONG *elems)
Definition: uia_utils.c:319
HRESULT write_runtime_id_base(SAFEARRAY *sa, HWND hwnd)
Definition: uia_utils.c:102
void uia_provider_thread_remove_node(HUIANODE node)
static struct uia_node * impl_from_IWineUiaNode(IWineUiaNode *iface)
Definition: uia_private.h:87
@ PROP_TYPE_ELEM_PROP
Definition: uia_private.h:31
@ PROP_TYPE_SPECIAL
Definition: uia_private.h:32
@ PROP_TYPE_PATTERN_PROP
Definition: uia_private.h:33
static void variant_init_bool(VARIANT *v, BOOL val)
Definition: uia_private.h:163
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
HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov)
@ PROV_METHOD_FLAG_RETURN_NODE_LRES
Definition: uia_private.h:214
static void variant_init_i4(VARIANT *v, int val)
Definition: uia_private.h:169
int uia_compare_safearrays(SAFEARRAY *sa1, SAFEARRAY *sa2, int prop_type)
Definition: uia_utils.c:334
static BOOL uia_array_reserve(void **elements, SIZE_T *capacity, SIZE_T count, SIZE_T size)
Definition: uia_private.h:186
@ TreeTraversalOptions_LastToFirstOrder
@ TreeTraversalOptions_Default
@ TreeScope_Descendants
@ TreeScope_Children
@ TreeScope_Element
ProviderOptions
@ ProviderOptions_ProviderOwnsSetFocus
@ ProviderOptions_ClientSideProvider
@ ProviderOptions_NonClientAreaProvider
@ ProviderOptions_UseClientCoordinates
@ ProviderOptions_OverrideProvider
@ ProviderOptions_HasNativeIAccessible
@ ProviderOptions_ServerSideProvider
@ ProviderOptions_UseComThreading
int PROPERTYID
NavigateDirection
@ NavigateDirection_NextSibling
@ NavigateDirection_PreviousSibling
@ NavigateDirection_Parent
@ NavigateDirection_LastChild
@ NavigateDirection_FirstChild
#define UIA_E_ELEMENTNOTAVAILABLE
@ ProviderType_BaseHwnd
@ ProviderType_Proxy
@ ProviderType_NonClientArea
NormalizeState
@ NormalizeState_View
@ NormalizeState_Custom
@ NormalizeState_None
SAFEARRAY *WINAPI UiaProviderCallback(HWND hwnd, enum ProviderType providerType)
#define UiaRootObjectId
#define UiaAppendRuntimeId
@ ConditionType_Not
@ ConditionType_True
@ ConditionType_Or
@ ConditionType_Property
@ ConditionType_False
@ ConditionType_And
@ AutomationIdentifierType_Property
Definition: dlist.c:348
HRESULT WINAPI DECLSPEC_HOTPATCH VariantClear(VARIANTARG *pVarg)
Definition: variant.c:648
void WINAPI VariantInit(VARIANTARG *pVarg)
Definition: variant.c:568
wchar_t tm const _CrtWcstime_Writes_and_advances_ptr_ count wchar_t ** out
Definition: wcsftime.cpp:383
#define OBJID_CLIENT
Definition: winable.h:19
#define CHILDID_SELF
Definition: winable.h:14
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
DWORD WINAPI GetCurrentThreadId(void)
Definition: thread.c:459
void WINAPI LeaveCriticalSection(LPCRITICAL_SECTION)
DWORD WINAPI GetCurrentProcessId(void)
Definition: proc.c:1156
DWORD WINAPI GetWindowThreadProcessId(HWND hWnd, PDWORD lpdwProcessId)
void WINAPI EnterCriticalSection(LPCRITICAL_SECTION)
#define WAIT_OBJECT_0
Definition: winbase.h:383
_In_ LONG _In_ HWND hwnd
Definition: winddi.h:4023
void * arg
Definition: msvc.h:10
#define WINAPI
Definition: msvc.h:6
#define S_FALSE
Definition: winerror.h:3451
#define E_NOINTERFACE
Definition: winerror.h:3479
#define NOERROR
Definition: winerror.h:3448
#define ERROR_INVALID_WINDOW_HANDLE
Definition: winerror.h:1226
#define HWND_MESSAGE
Definition: winuser.h:1221
BOOL WINAPI IsWindow(_In_opt_ HWND)
BOOL WINAPI TranslateMessage(_In_ const MSG *)
LRESULT WINAPI DefWindowProcW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
BOOL WINAPI GetMessageW(_Out_ LPMSG, _In_opt_ HWND, _In_ UINT, _In_ UINT)
BOOL WINAPI PostMessageW(_In_opt_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
int WINAPIV wsprintfW(_Out_ LPWSTR, _In_ _Printf_format_string_ LPCWSTR,...)
HWND WINAPI GetDesktopWindow(void)
Definition: window.c:628
#define CreateWindowW(a, b, c, d, e, f, g, h, i, j, k)
Definition: winuser.h:4470
LRESULT WINAPI DispatchMessageW(_In_ const MSG *)
#define SetWindowLongPtrW
Definition: winuser.h:5512
BOOL WINAPI DestroyWindow(_In_ HWND)
LRESULT WINAPI SendMessageW(_In_ HWND, _In_ UINT, _In_ WPARAM, _In_ LPARAM)
__wchar_t WCHAR
Definition: xmlstorage.h:180