kernelbase: Let GetModuleBaseName succeed on 64bit modules in wow64.
[wine.git] / dlls / uiautomationcore / uia_provider.c
blobfc718fabe43f28b5b369f6bb92bde87399a13621
1 /*
2 * Copyright 2022 Connor McAdams for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19 #include "uia_private.h"
20 #include "ocidl.h"
22 #include "wine/debug.h"
23 #include "wine/heap.h"
24 #include "wine/rbtree.h"
25 #include "initguid.h"
26 #include "wine/iaccessible2.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
30 DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
32 static void variant_init_i4(VARIANT *v, int val)
34 V_VT(v) = VT_I4;
35 V_I4(v) = val;
38 static void variant_init_bool(VARIANT *v, BOOL val)
40 V_VT(v) = VT_BOOL;
41 V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE;
44 static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
46 HRESULT hr;
47 VARIANT v;
49 VariantInit(&v);
50 hr = IAccessible_get_accState(acc, cid, &v);
51 if (SUCCEEDED(hr) && V_VT(&v) == VT_I4 && (V_I4(&v) & flag))
52 return TRUE;
54 return FALSE;
57 static IAccessible2 *msaa_acc_get_ia2(IAccessible *acc)
59 IServiceProvider *serv_prov;
60 IAccessible2 *ia2 = NULL;
61 HRESULT hr;
63 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
64 if (SUCCEEDED(hr))
66 hr = IServiceProvider_QueryService(serv_prov, &IID_IAccessible2, &IID_IAccessible2, (void **)&ia2);
67 IServiceProvider_Release(serv_prov);
68 if (SUCCEEDED(hr) && ia2)
69 return ia2;
72 hr = IAccessible_QueryInterface(acc, &IID_IAccessible2, (void **)&ia2);
73 if (SUCCEEDED(hr) && ia2)
74 return ia2;
76 return NULL;
79 static IAccessible *msaa_acc_da_unwrap(IAccessible *acc)
81 IServiceProvider *sp;
82 IAccessible *acc2;
83 HRESULT hr;
85 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp);
86 if (SUCCEEDED(hr))
88 hr = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper, &IID_IAccessible, (void**)&acc2);
89 IServiceProvider_Release(sp);
92 if (SUCCEEDED(hr) && acc2)
93 return acc2;
95 IAccessible_AddRef(acc);
96 return acc;
100 * Compare role, state, child count, and location properties of the two
101 * IAccessibles. If all four are successfully retrieved and are equal, this is
102 * considered a match.
104 static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2)
106 BOOL role_match, state_match, child_count_match, location_match;
107 LONG child_count[2], left[2], top[2], width[2], height[2];
108 VARIANT cid, v, v2;
109 HRESULT hr, hr2;
111 role_match = state_match = child_count_match = location_match = FALSE;
112 variant_init_i4(&cid, CHILDID_SELF);
113 hr = IAccessible_get_accRole(acc, cid, &v);
114 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
116 VariantInit(&v2);
117 hr = IAccessible_get_accRole(acc2, cid, &v2);
118 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
120 if (V_I4(&v) != V_I4(&v2))
121 return E_FAIL;
123 role_match = TRUE;
127 VariantInit(&v);
128 hr = IAccessible_get_accState(acc, cid, &v);
129 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
131 VariantInit(&v2);
132 hr = IAccessible_get_accState(acc2, cid, &v2);
133 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
135 if (V_I4(&v) != V_I4(&v2))
136 return E_FAIL;
138 state_match = TRUE;
142 hr = IAccessible_get_accChildCount(acc, &child_count[0]);
143 hr2 = IAccessible_get_accChildCount(acc2, &child_count[1]);
144 if (SUCCEEDED(hr) && SUCCEEDED(hr2))
146 if (child_count[0] != child_count[1])
147 return E_FAIL;
149 child_count_match = TRUE;
152 hr = IAccessible_accLocation(acc, &left[0], &top[0], &width[0], &height[0], cid);
153 if (SUCCEEDED(hr))
155 hr = IAccessible_accLocation(acc2, &left[1], &top[1], &width[1], &height[1], cid);
156 if (SUCCEEDED(hr))
158 if ((left[0] != left[1]) || (top[0] != top[1]) || (width[0] != width[1]) ||
159 (height[0] != height[1]))
160 return E_FAIL;
162 location_match = TRUE;
166 if (role_match && state_match && child_count_match && location_match)
167 return S_OK;
169 return S_FALSE;
172 static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
174 IAccessible2 *ia2[2] = { NULL, NULL };
175 IUnknown *unk, *unk2;
176 BOOL matched = FALSE;
177 LONG unique_id[2];
178 BSTR name[2];
179 VARIANT cid;
180 HRESULT hr;
182 acc = msaa_acc_da_unwrap(acc);
183 acc2 = msaa_acc_da_unwrap(acc2);
184 IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk);
185 IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2);
186 if (unk == unk2)
188 matched = TRUE;
189 goto exit;
192 ia2[0] = msaa_acc_get_ia2(acc);
193 ia2[1] = msaa_acc_get_ia2(acc2);
194 if (!ia2[0] != !ia2[1])
195 goto exit;
196 if (ia2[0])
198 hr = IAccessible2_get_uniqueID(ia2[0], &unique_id[0]);
199 if (SUCCEEDED(hr))
201 hr = IAccessible2_get_uniqueID(ia2[1], &unique_id[1]);
202 if (SUCCEEDED(hr))
204 if (unique_id[0] == unique_id[1])
205 matched = TRUE;
207 goto exit;
212 hr = msaa_acc_prop_match(acc, acc2);
213 if (FAILED(hr))
214 goto exit;
215 if (hr == S_OK)
216 matched = TRUE;
218 variant_init_i4(&cid, CHILDID_SELF);
219 hr = IAccessible_get_accName(acc, cid, &name[0]);
220 if (SUCCEEDED(hr))
222 hr = IAccessible_get_accName(acc2, cid, &name[1]);
223 if (SUCCEEDED(hr))
225 if (!name[0] && !name[1])
226 matched = TRUE;
227 else if (!name[0] || !name[1])
228 matched = FALSE;
229 else
231 if (!wcscmp(name[0], name[1]))
232 matched = TRUE;
233 else
234 matched = FALSE;
237 SysFreeString(name[1]);
240 SysFreeString(name[0]);
243 exit:
244 IUnknown_Release(unk);
245 IUnknown_Release(unk2);
246 IAccessible_Release(acc);
247 IAccessible_Release(acc2);
248 if (ia2[0])
249 IAccessible2_Release(ia2[0]);
250 if (ia2[1])
251 IAccessible2_Release(ia2[1]);
253 return matched;
256 static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent)
258 IDispatch *disp = NULL;
259 HRESULT hr;
261 *parent = NULL;
262 hr = IAccessible_get_accParent(acc, &disp);
263 if (FAILED(hr) || !disp)
264 return hr;
266 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void**)parent);
267 IDispatch_Release(disp);
268 return hr;
271 #define DIR_FORWARD 0
272 #define DIR_REVERSE 1
273 static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction,
274 IAccessible **child, LONG *child_id, LONG *child_pos, BOOL check_visible)
276 LONG child_count, cur_pos;
277 IDispatch *disp;
278 VARIANT cid;
279 HRESULT hr;
281 *child = NULL;
282 *child_id = 0;
283 cur_pos = start_pos;
284 while (1)
286 hr = IAccessible_get_accChildCount(acc, &child_count);
287 if (FAILED(hr) || (cur_pos > child_count))
288 break;
290 variant_init_i4(&cid, cur_pos);
291 hr = IAccessible_get_accChild(acc, cid, &disp);
292 if (FAILED(hr))
293 break;
295 if (hr == S_FALSE)
297 if (!check_visible || !msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE))
299 *child = acc;
300 *child_id = *child_pos = cur_pos;
301 IAccessible_AddRef(acc);
302 return S_OK;
305 else
307 IAccessible *acc_child = NULL;
309 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)&acc_child);
310 IDispatch_Release(disp);
311 if (FAILED(hr))
312 break;
314 variant_init_i4(&cid, CHILDID_SELF);
315 if (!check_visible || !msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE))
317 *child = acc_child;
318 *child_id = CHILDID_SELF;
319 *child_pos = cur_pos;
320 return S_OK;
323 IAccessible_Release(acc_child);
326 if (direction == DIR_FORWARD)
327 cur_pos++;
328 else
329 cur_pos--;
331 if ((cur_pos > child_count) || (cur_pos <= 0))
332 break;
335 return hr;
338 static HRESULT msaa_acc_get_child_pos(IAccessible *acc, IAccessible **out_parent,
339 LONG *out_child_pos)
341 LONG child_count, child_id, child_pos, match_pos;
342 IAccessible *child, *parent, *match, **children;
343 HRESULT hr;
344 int i;
346 *out_parent = NULL;
347 *out_child_pos = 0;
348 hr = msaa_acc_get_parent(acc, &parent);
349 if (FAILED(hr) || !parent)
350 return hr;
352 hr = IAccessible_get_accChildCount(parent, &child_count);
353 if (FAILED(hr) || !child_count)
355 IAccessible_Release(parent);
356 return hr;
359 children = heap_alloc_zero(sizeof(*children) * child_count);
360 if (!children)
361 return E_OUTOFMEMORY;
363 match = NULL;
364 for (i = 0; i < child_count; i++)
366 hr = msaa_acc_get_next_child(parent, i + 1, DIR_FORWARD, &child, &child_id, &child_pos, FALSE);
367 if (FAILED(hr) || !child)
368 goto exit;
370 if (child != parent)
371 children[i] = child;
372 else
373 IAccessible_Release(child);
376 for (i = 0; i < child_count; i++)
378 if (!children[i])
379 continue;
381 if (msaa_acc_compare(acc, children[i]))
383 if (!match)
385 match = children[i];
386 match_pos = i + 1;
388 /* Can't have more than one IAccessible match. */
389 else
391 match = NULL;
392 match_pos = 0;
393 break;
398 exit:
399 if (match)
401 *out_parent = parent;
402 *out_child_pos = match_pos;
404 else
405 IAccessible_Release(parent);
407 for (i = 0; i < child_count; i++)
409 if (children[i])
410 IAccessible_Release(children[i]);
413 heap_free(children);
415 return hr;
418 static LONG msaa_role_to_uia_control_type(LONG role)
420 switch (role)
422 case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId;
423 case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId;
424 case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId;
425 case ROLE_SYSTEM_INDICATOR:
426 case ROLE_SYSTEM_GRIP: return UIA_ThumbControlTypeId;
427 case ROLE_SYSTEM_APPLICATION:
428 case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId;
429 case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId;
430 case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId;
431 case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId;
432 case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId;
433 case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId;
434 case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId;
435 case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId;
436 case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId;
437 case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId;
438 case ROLE_SYSTEM_COLUMNHEADER:
439 case ROLE_SYSTEM_ROWHEADER: return UIA_HeaderControlTypeId;
440 case ROLE_SYSTEM_CELL: return UIA_DataItemControlTypeId;
441 case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId;
442 case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId;
443 case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId;
444 case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId;
445 case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId;
446 case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId;
447 case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId;
448 case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId;
449 case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId;
450 case ROLE_SYSTEM_CLOCK:
451 case ROLE_SYSTEM_BUTTONDROPDOWNGRID:
452 case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId;
453 case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId;
454 case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId;
455 case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId;
456 case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId;
457 case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId;
458 case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId;
459 case ROLE_SYSTEM_BUTTONMENU:
460 case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId;
461 case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId;
462 case ROLE_SYSTEM_BUTTONDROPDOWN:
463 case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId;
464 case ROLE_SYSTEM_SOUND:
465 case ROLE_SYSTEM_CURSOR:
466 case ROLE_SYSTEM_CARET:
467 case ROLE_SYSTEM_ALERT:
468 case ROLE_SYSTEM_CLIENT:
469 case ROLE_SYSTEM_CHART:
470 case ROLE_SYSTEM_DIALOG:
471 case ROLE_SYSTEM_BORDER:
472 case ROLE_SYSTEM_COLUMN:
473 case ROLE_SYSTEM_ROW:
474 case ROLE_SYSTEM_HELPBALLOON:
475 case ROLE_SYSTEM_CHARACTER:
476 case ROLE_SYSTEM_PROPERTYPAGE:
477 case ROLE_SYSTEM_DROPLIST:
478 case ROLE_SYSTEM_DIAL:
479 case ROLE_SYSTEM_HOTKEYFIELD:
480 case ROLE_SYSTEM_DIAGRAM:
481 case ROLE_SYSTEM_ANIMATION:
482 case ROLE_SYSTEM_EQUATION:
483 case ROLE_SYSTEM_WHITESPACE:
484 case ROLE_SYSTEM_IPADDRESS:
485 case ROLE_SYSTEM_OUTLINEBUTTON:
486 WARN("No UIA control type mapping for MSAA role %ld\n", role);
487 break;
489 default:
490 FIXME("UIA control type mapping unimplemented for MSAA role %ld\n", role);
491 break;
494 return 0;
498 * UiaProviderFromIAccessible IRawElementProviderSimple interface.
500 struct msaa_provider {
501 IRawElementProviderSimple IRawElementProviderSimple_iface;
502 IRawElementProviderFragment IRawElementProviderFragment_iface;
503 ILegacyIAccessibleProvider ILegacyIAccessibleProvider_iface;
504 LONG refcount;
506 IAccessible *acc;
507 IAccessible2 *ia2;
508 VARIANT cid;
509 HWND hwnd;
510 LONG control_type;
512 BOOL root_acc_check_ran;
513 BOOL is_root_acc;
515 IAccessible *parent;
516 INT child_pos;
519 static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov)
521 IAccessible *acc;
522 HRESULT hr;
524 if (msaa_prov->root_acc_check_ran)
525 return msaa_prov->is_root_acc;
527 msaa_prov->root_acc_check_ran = TRUE;
528 if (V_I4(&msaa_prov->cid) != CHILDID_SELF || msaa_prov->parent)
529 return FALSE;
531 hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
532 if (FAILED(hr))
533 return FALSE;
535 if (msaa_acc_compare(msaa_prov->acc, acc))
536 msaa_prov->is_root_acc = TRUE;
538 IAccessible_Release(acc);
539 return msaa_prov->is_root_acc;
542 static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
544 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
547 HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
549 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
551 *ppv = NULL;
552 if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
553 *ppv = iface;
554 else if (IsEqualIID(riid, &IID_IRawElementProviderFragment))
555 *ppv = &msaa_prov->IRawElementProviderFragment_iface;
556 else if (IsEqualIID(riid, &IID_ILegacyIAccessibleProvider))
557 *ppv = &msaa_prov->ILegacyIAccessibleProvider_iface;
558 else
559 return E_NOINTERFACE;
561 IRawElementProviderSimple_AddRef(iface);
562 return S_OK;
565 ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface)
567 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
568 ULONG refcount = InterlockedIncrement(&msaa_prov->refcount);
570 TRACE("%p, refcount %ld\n", iface, refcount);
572 return refcount;
575 ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
577 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
578 ULONG refcount = InterlockedDecrement(&msaa_prov->refcount);
580 TRACE("%p, refcount %ld\n", iface, refcount);
582 if (!refcount)
584 IAccessible_Release(msaa_prov->acc);
585 if (msaa_prov->parent)
586 IAccessible_Release(msaa_prov->parent);
587 if (msaa_prov->ia2)
588 IAccessible2_Release(msaa_prov->ia2);
589 heap_free(msaa_prov);
592 return refcount;
595 HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
596 enum ProviderOptions *ret_val)
598 TRACE("%p, %p\n", iface, ret_val);
599 *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading;
600 return S_OK;
603 HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface,
604 PATTERNID pattern_id, IUnknown **ret_val)
606 TRACE("%p, %d, %p\n", iface, pattern_id, ret_val);
608 *ret_val = NULL;
609 switch (pattern_id)
611 case UIA_LegacyIAccessiblePatternId:
612 return IRawElementProviderSimple_QueryInterface(iface, &IID_IUnknown, (void **)ret_val);
614 default:
615 FIXME("Unimplemented patternId %d\n", pattern_id);
616 break;
619 return S_OK;
622 HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
623 PROPERTYID prop_id, VARIANT *ret_val)
625 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
626 HRESULT hr;
627 VARIANT v;
629 TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
631 VariantInit(ret_val);
632 VariantInit(&v);
633 switch (prop_id)
635 case UIA_ProviderDescriptionPropertyId:
636 V_VT(ret_val) = VT_BSTR;
637 V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
638 break;
640 case UIA_ControlTypePropertyId:
641 if (!msaa_prov->control_type)
643 hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
644 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
645 msaa_prov->control_type = msaa_role_to_uia_control_type(V_I4(&v));
648 if (msaa_prov->control_type)
649 variant_init_i4(ret_val, msaa_prov->control_type);
651 break;
653 case UIA_HasKeyboardFocusPropertyId:
654 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
655 STATE_SYSTEM_FOCUSED));
656 break;
658 case UIA_IsKeyboardFocusablePropertyId:
659 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
660 STATE_SYSTEM_FOCUSABLE));
661 break;
663 case UIA_IsEnabledPropertyId:
664 variant_init_bool(ret_val, !msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
665 STATE_SYSTEM_UNAVAILABLE));
666 break;
668 case UIA_IsPasswordPropertyId:
669 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
670 STATE_SYSTEM_PROTECTED));
671 break;
673 default:
674 FIXME("Unimplemented propertyId %d\n", prop_id);
675 break;
678 return S_OK;
681 HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
682 IRawElementProviderSimple **ret_val)
684 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
686 TRACE("%p, %p\n", iface, ret_val);
688 *ret_val = NULL;
689 if (msaa_check_root_acc(msaa_prov))
690 return UiaHostProviderFromHwnd(msaa_prov->hwnd, ret_val);
692 return S_OK;
695 static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
696 msaa_provider_QueryInterface,
697 msaa_provider_AddRef,
698 msaa_provider_Release,
699 msaa_provider_get_ProviderOptions,
700 msaa_provider_GetPatternProvider,
701 msaa_provider_GetPropertyValue,
702 msaa_provider_get_HostRawElementProvider,
706 * IRawElementProviderFragment interface for UiaProviderFromIAccessible
707 * providers.
709 static inline struct msaa_provider *impl_from_msaa_fragment(IRawElementProviderFragment *iface)
711 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderFragment_iface);
714 static HRESULT WINAPI msaa_fragment_QueryInterface(IRawElementProviderFragment *iface, REFIID riid,
715 void **ppv)
717 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
718 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
721 static ULONG WINAPI msaa_fragment_AddRef(IRawElementProviderFragment *iface)
723 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
724 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
727 static ULONG WINAPI msaa_fragment_Release(IRawElementProviderFragment *iface)
729 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
730 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
733 static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
734 enum NavigateDirection direction, IRawElementProviderFragment **ret_val)
736 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
737 LONG child_count, child_id, child_pos;
738 IRawElementProviderSimple *elprov;
739 IAccessible *acc;
740 HRESULT hr;
742 TRACE("%p, %d, %p\n", iface, direction, ret_val);
744 *ret_val = NULL;
745 switch (direction)
747 case NavigateDirection_Parent:
748 if (msaa_check_root_acc(msaa_prov))
749 break;
751 if (V_I4(&msaa_prov->cid) == CHILDID_SELF)
753 hr = msaa_acc_get_parent(msaa_prov->acc, &acc);
754 if (FAILED(hr) || !acc)
755 break;
757 else
758 acc = msaa_prov->acc;
760 hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov);
761 if (SUCCEEDED(hr))
763 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
764 *ret_val = &prov->IRawElementProviderFragment_iface;
767 if (acc != msaa_prov->acc)
768 IAccessible_Release(acc);
770 break;
772 case NavigateDirection_FirstChild:
773 case NavigateDirection_LastChild:
774 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
775 break;
777 hr = IAccessible_get_accChildCount(msaa_prov->acc, &child_count);
778 if (FAILED(hr) || !child_count)
779 break;
781 if (direction == NavigateDirection_FirstChild)
782 hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id,
783 &child_pos, TRUE);
784 else
785 hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id,
786 &child_pos, TRUE);
788 if (FAILED(hr) || !acc)
789 break;
791 hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
792 if (SUCCEEDED(hr))
794 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
796 *ret_val = &prov->IRawElementProviderFragment_iface;
797 prov->parent = msaa_prov->acc;
798 IAccessible_AddRef(msaa_prov->acc);
799 if (acc != msaa_prov->acc)
800 prov->child_pos = child_pos;
801 else
802 prov->child_pos = child_id;
804 IAccessible_Release(acc);
806 break;
808 case NavigateDirection_NextSibling:
809 case NavigateDirection_PreviousSibling:
810 if (msaa_check_root_acc(msaa_prov))
811 break;
813 if (!msaa_prov->parent)
815 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
817 msaa_prov->parent = msaa_prov->acc;
818 IAccessible_AddRef(msaa_prov->acc);
819 msaa_prov->child_pos = V_I4(&msaa_prov->cid);
821 else
823 hr = msaa_acc_get_child_pos(msaa_prov->acc, &acc, &child_pos);
824 if (FAILED(hr) || !acc)
825 break;
826 msaa_prov->parent = acc;
827 msaa_prov->child_pos = child_pos;
831 if (direction == NavigateDirection_NextSibling)
832 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos + 1, DIR_FORWARD,
833 &acc, &child_id, &child_pos, TRUE);
834 else
835 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos - 1, DIR_REVERSE,
836 &acc, &child_id, &child_pos, TRUE);
838 if (FAILED(hr) || !acc)
839 break;
841 hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
842 if (SUCCEEDED(hr))
844 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
846 *ret_val = &prov->IRawElementProviderFragment_iface;
847 prov->parent = msaa_prov->parent;
848 IAccessible_AddRef(msaa_prov->parent);
849 if (acc != msaa_prov->acc)
850 prov->child_pos = child_pos;
851 else
852 prov->child_pos = child_id;
854 IAccessible_Release(acc);
856 break;
858 default:
859 FIXME("Invalid NavigateDirection %d\n", direction);
860 return E_INVALIDARG;
863 return S_OK;
866 static HRESULT WINAPI msaa_fragment_GetRuntimeId(IRawElementProviderFragment *iface,
867 SAFEARRAY **ret_val)
869 FIXME("%p, %p: stub!\n", iface, ret_val);
870 *ret_val = NULL;
871 return E_NOTIMPL;
874 static HRESULT WINAPI msaa_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface,
875 struct UiaRect *ret_val)
877 FIXME("%p, %p: stub!\n", iface, ret_val);
878 return E_NOTIMPL;
881 static HRESULT WINAPI msaa_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface,
882 SAFEARRAY **ret_val)
884 FIXME("%p, %p: stub!\n", iface, ret_val);
885 *ret_val = NULL;
886 return E_NOTIMPL;
889 static HRESULT WINAPI msaa_fragment_SetFocus(IRawElementProviderFragment *iface)
891 FIXME("%p: stub!\n", iface);
892 return E_NOTIMPL;
895 static HRESULT WINAPI msaa_fragment_get_FragmentRoot(IRawElementProviderFragment *iface,
896 IRawElementProviderFragmentRoot **ret_val)
898 FIXME("%p, %p: stub!\n", iface, ret_val);
899 *ret_val = NULL;
900 return E_NOTIMPL;
903 static const IRawElementProviderFragmentVtbl msaa_fragment_vtbl = {
904 msaa_fragment_QueryInterface,
905 msaa_fragment_AddRef,
906 msaa_fragment_Release,
907 msaa_fragment_Navigate,
908 msaa_fragment_GetRuntimeId,
909 msaa_fragment_get_BoundingRectangle,
910 msaa_fragment_GetEmbeddedFragmentRoots,
911 msaa_fragment_SetFocus,
912 msaa_fragment_get_FragmentRoot,
916 * ILegacyIAccessibleProvider interface for UiaProviderFromIAccessible
917 * providers.
919 static inline struct msaa_provider *impl_from_msaa_acc_provider(ILegacyIAccessibleProvider *iface)
921 return CONTAINING_RECORD(iface, struct msaa_provider, ILegacyIAccessibleProvider_iface);
924 static HRESULT WINAPI msaa_acc_provider_QueryInterface(ILegacyIAccessibleProvider *iface, REFIID riid, void **ppv)
926 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
927 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
930 static ULONG WINAPI msaa_acc_provider_AddRef(ILegacyIAccessibleProvider *iface)
932 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
933 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
936 static ULONG WINAPI msaa_acc_provider_Release(ILegacyIAccessibleProvider *iface)
938 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
939 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
942 static HRESULT WINAPI msaa_acc_provider_Select(ILegacyIAccessibleProvider *iface, LONG select_flags)
944 FIXME("%p, %#lx: stub!\n", iface, select_flags);
945 return E_NOTIMPL;
948 static HRESULT WINAPI msaa_acc_provider_DoDefaultAction(ILegacyIAccessibleProvider *iface)
950 FIXME("%p: stub!\n", iface);
951 return E_NOTIMPL;
954 static HRESULT WINAPI msaa_acc_provider_SetValue(ILegacyIAccessibleProvider *iface, LPCWSTR val)
956 FIXME("%p, %p<%s>: stub!\n", iface, val, debugstr_w(val));
957 return E_NOTIMPL;
960 static HRESULT WINAPI msaa_acc_provider_GetIAccessible(ILegacyIAccessibleProvider *iface,
961 IAccessible **out_acc)
963 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
965 TRACE("%p, %p\n", iface, out_acc);
967 IAccessible_AddRef(msaa_prov->acc);
968 *out_acc = msaa_prov->acc;
970 return S_OK;
973 static HRESULT WINAPI msaa_acc_provider_get_ChildId(ILegacyIAccessibleProvider *iface, int *out_cid)
975 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
977 TRACE("%p, %p\n", iface, out_cid);
978 *out_cid = V_I4(&msaa_prov->cid);
980 return S_OK;
983 static HRESULT WINAPI msaa_acc_provider_get_Name(ILegacyIAccessibleProvider *iface, BSTR *out_name)
985 FIXME("%p, %p: stub!\n", iface, out_name);
986 return E_NOTIMPL;
989 static HRESULT WINAPI msaa_acc_provider_get_Value(ILegacyIAccessibleProvider *iface, BSTR *out_value)
991 FIXME("%p, %p: stub!\n", iface, out_value);
992 return E_NOTIMPL;
995 static HRESULT WINAPI msaa_acc_provider_get_Description(ILegacyIAccessibleProvider *iface,
996 BSTR *out_description)
998 FIXME("%p, %p: stub!\n", iface, out_description);
999 return E_NOTIMPL;
1002 static HRESULT WINAPI msaa_acc_provider_get_Role(ILegacyIAccessibleProvider *iface, DWORD *out_role)
1004 FIXME("%p, %p: stub!\n", iface, out_role);
1005 return E_NOTIMPL;
1008 static HRESULT WINAPI msaa_acc_provider_get_State(ILegacyIAccessibleProvider *iface, DWORD *out_state)
1010 FIXME("%p, %p: stub!\n", iface, out_state);
1011 return E_NOTIMPL;
1014 static HRESULT WINAPI msaa_acc_provider_get_Help(ILegacyIAccessibleProvider *iface, BSTR *out_help)
1016 FIXME("%p, %p: stub!\n", iface, out_help);
1017 return E_NOTIMPL;
1020 static HRESULT WINAPI msaa_acc_provider_get_KeyboardShortcut(ILegacyIAccessibleProvider *iface,
1021 BSTR *out_kbd_shortcut)
1023 FIXME("%p, %p: stub!\n", iface, out_kbd_shortcut);
1024 return E_NOTIMPL;
1027 static HRESULT WINAPI msaa_acc_provider_GetSelection(ILegacyIAccessibleProvider *iface,
1028 SAFEARRAY **out_selected)
1030 FIXME("%p, %p: stub!\n", iface, out_selected);
1031 return E_NOTIMPL;
1034 static HRESULT WINAPI msaa_acc_provider_get_DefaultAction(ILegacyIAccessibleProvider *iface,
1035 BSTR *out_default_action)
1037 FIXME("%p, %p: stub!\n", iface, out_default_action);
1038 return E_NOTIMPL;
1041 static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = {
1042 msaa_acc_provider_QueryInterface,
1043 msaa_acc_provider_AddRef,
1044 msaa_acc_provider_Release,
1045 msaa_acc_provider_Select,
1046 msaa_acc_provider_DoDefaultAction,
1047 msaa_acc_provider_SetValue,
1048 msaa_acc_provider_GetIAccessible,
1049 msaa_acc_provider_get_ChildId,
1050 msaa_acc_provider_get_Name,
1051 msaa_acc_provider_get_Value,
1052 msaa_acc_provider_get_Description,
1053 msaa_acc_provider_get_Role,
1054 msaa_acc_provider_get_State,
1055 msaa_acc_provider_get_Help,
1056 msaa_acc_provider_get_KeyboardShortcut,
1057 msaa_acc_provider_GetSelection,
1058 msaa_acc_provider_get_DefaultAction,
1061 /***********************************************************************
1062 * UiaProviderFromIAccessible (uiautomationcore.@)
1064 HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
1065 IRawElementProviderSimple **elprov)
1067 struct msaa_provider *msaa_prov;
1068 IServiceProvider *serv_prov;
1069 HWND hwnd = NULL;
1070 HRESULT hr;
1072 TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
1074 if (elprov)
1075 *elprov = NULL;
1077 if (!elprov)
1078 return E_POINTER;
1079 if (!acc)
1080 return E_INVALIDARG;
1082 if (flags != UIA_PFIA_DEFAULT)
1084 FIXME("unsupported flags %#lx\n", flags);
1085 return E_NOTIMPL;
1088 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
1089 if (SUCCEEDED(hr))
1091 IUnknown *unk;
1093 hr = IServiceProvider_QueryService(serv_prov, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk);
1094 if (SUCCEEDED(hr))
1096 WARN("Cannot wrap an oleacc proxy IAccessible!\n");
1097 IUnknown_Release(unk);
1098 IServiceProvider_Release(serv_prov);
1099 return E_INVALIDARG;
1102 IServiceProvider_Release(serv_prov);
1105 hr = WindowFromAccessibleObject(acc, &hwnd);
1106 if (FAILED(hr))
1107 return hr;
1108 if (!hwnd)
1109 return E_FAIL;
1111 msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
1112 if (!msaa_prov)
1113 return E_OUTOFMEMORY;
1115 msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
1116 msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
1117 msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
1118 msaa_prov->refcount = 1;
1119 msaa_prov->hwnd = hwnd;
1120 variant_init_i4(&msaa_prov->cid, child_id);
1121 msaa_prov->acc = acc;
1122 IAccessible_AddRef(acc);
1123 msaa_prov->ia2 = msaa_acc_get_ia2(acc);
1124 *elprov = &msaa_prov->IRawElementProviderSimple_iface;
1126 return S_OK;
1130 * UI Automation provider thread functions.
1132 struct uia_provider_thread
1134 struct rb_tree node_map;
1135 struct list nodes_list;
1136 HANDLE hthread;
1137 HWND hwnd;
1138 LONG ref;
1141 static struct uia_provider_thread provider_thread;
1142 static CRITICAL_SECTION provider_thread_cs;
1143 static CRITICAL_SECTION_DEBUG provider_thread_cs_debug =
1145 0, 0, &provider_thread_cs,
1146 { &provider_thread_cs_debug.ProcessLocksList, &provider_thread_cs_debug.ProcessLocksList },
1147 0, 0, { (DWORD_PTR)(__FILE__ ": provider_thread_cs") }
1149 static CRITICAL_SECTION provider_thread_cs = { &provider_thread_cs_debug, -1, 0, 0, 0, 0 };
1151 struct uia_provider_thread_map_entry
1153 struct rb_entry entry;
1155 SAFEARRAY *runtime_id;
1156 struct list nodes_list;
1159 static int uia_runtime_id_compare(const void *key, const struct rb_entry *entry)
1161 struct uia_provider_thread_map_entry *prov_entry = RB_ENTRY_VALUE(entry, struct uia_provider_thread_map_entry, entry);
1162 return uia_compare_safearrays(prov_entry->runtime_id, (SAFEARRAY *)key, UIAutomationType_IntArray);
1165 void uia_provider_thread_remove_node(HUIANODE node)
1167 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1169 TRACE("Removing node %p\n", node);
1171 EnterCriticalSection(&provider_thread_cs);
1173 list_remove(&node_data->prov_thread_list_entry);
1174 list_init(&node_data->prov_thread_list_entry);
1175 if (!list_empty(&node_data->node_map_list_entry))
1177 list_remove(&node_data->node_map_list_entry);
1178 list_init(&node_data->node_map_list_entry);
1179 if (list_empty(&node_data->map->nodes_list))
1181 rb_remove(&provider_thread.node_map, &node_data->map->entry);
1182 SafeArrayDestroy(node_data->map->runtime_id);
1183 heap_free(node_data->map);
1185 node_data->map = NULL;
1188 LeaveCriticalSection(&provider_thread_cs);
1191 static void uia_provider_thread_disconnect_node(SAFEARRAY *sa)
1193 struct rb_entry *rb_entry;
1195 EnterCriticalSection(&provider_thread_cs);
1197 /* Provider thread hasn't been started, no nodes to disconnect. */
1198 if (!provider_thread.ref)
1199 goto exit;
1201 rb_entry = rb_get(&provider_thread.node_map, sa);
1202 if (rb_entry)
1204 struct uia_provider_thread_map_entry *prov_map;
1205 struct list *cursor, *cursor2;
1206 struct uia_node *node_data;
1208 prov_map = RB_ENTRY_VALUE(rb_entry, struct uia_provider_thread_map_entry, entry);
1209 LIST_FOR_EACH_SAFE(cursor, cursor2, &prov_map->nodes_list)
1211 node_data = LIST_ENTRY(cursor, struct uia_node, node_map_list_entry);
1213 list_remove(cursor);
1214 list_remove(&node_data->prov_thread_list_entry);
1215 list_init(&node_data->prov_thread_list_entry);
1216 list_init(&node_data->node_map_list_entry);
1217 node_data->map = NULL;
1219 IWineUiaNode_disconnect(&node_data->IWineUiaNode_iface);
1222 rb_remove(&provider_thread.node_map, &prov_map->entry);
1223 SafeArrayDestroy(prov_map->runtime_id);
1224 heap_free(prov_map);
1227 exit:
1228 LeaveCriticalSection(&provider_thread_cs);
1231 static HRESULT uia_provider_thread_add_node(HUIANODE node)
1233 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1234 int prov_type = get_node_provider_type_at_idx(node_data, 0);
1235 struct uia_provider *prov_data;
1236 SAFEARRAY *sa;
1237 HRESULT hr;
1239 prov_data = impl_from_IWineUiaProvider(node_data->prov[prov_type]);
1240 node_data->nested_node = prov_data->return_nested_node = TRUE;
1241 hr = UiaGetRuntimeId(node, &sa);
1242 if (FAILED(hr))
1243 return hr;
1245 TRACE("Adding node %p\n", node);
1247 EnterCriticalSection(&provider_thread_cs);
1248 list_add_tail(&provider_thread.nodes_list, &node_data->prov_thread_list_entry);
1250 /* If we have a runtime ID, create an entry in the rb tree. */
1251 if (sa)
1253 struct uia_provider_thread_map_entry *prov_map;
1254 struct rb_entry *rb_entry;
1256 if ((rb_entry = rb_get(&provider_thread.node_map, sa)))
1258 prov_map = RB_ENTRY_VALUE(rb_entry, struct uia_provider_thread_map_entry, entry);
1259 SafeArrayDestroy(sa);
1261 else
1263 prov_map = heap_alloc_zero(sizeof(*prov_map));
1264 if (!prov_map)
1266 SafeArrayDestroy(sa);
1267 LeaveCriticalSection(&provider_thread_cs);
1268 return E_OUTOFMEMORY;
1271 prov_map->runtime_id = sa;
1272 list_init(&prov_map->nodes_list);
1273 rb_put(&provider_thread.node_map, sa, &prov_map->entry);
1276 list_add_tail(&prov_map->nodes_list, &node_data->node_map_list_entry);
1277 node_data->map = prov_map;
1280 LeaveCriticalSection(&provider_thread_cs);
1282 return S_OK;
1285 #define WM_GET_OBJECT_UIA_NODE (WM_USER + 1)
1286 #define WM_UIA_PROVIDER_THREAD_STOP (WM_USER + 2)
1287 static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam,
1288 LPARAM lparam)
1290 switch (msg)
1292 case WM_GET_OBJECT_UIA_NODE:
1294 HUIANODE node = (HUIANODE)lparam;
1295 LRESULT lr;
1297 if (FAILED(uia_provider_thread_add_node(node)))
1299 WARN("Failed to add node %p to provider thread list.\n", node);
1300 UiaNodeRelease(node);
1301 return 0;
1305 * LresultFromObject returns an index into the global atom string table,
1306 * which has a valid range of 0xc000-0xffff.
1308 lr = LresultFromObject(&IID_IWineUiaNode, 0, (IUnknown *)node);
1309 if ((lr > 0xffff) || (lr < 0xc000))
1311 WARN("Got invalid lresult %Ix\n", lr);
1312 lr = 0;
1316 * LresultFromObject increases refcnt by 1. If LresultFromObject
1317 * failed, this is expected to release the node.
1319 UiaNodeRelease(node);
1320 return lr;
1323 default:
1324 break;
1327 return DefWindowProcW(hwnd, msg, wparam, lparam);
1330 static DWORD WINAPI uia_provider_thread_proc(void *arg)
1332 HANDLE initialized_event = arg;
1333 HWND hwnd;
1334 MSG msg;
1336 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1337 hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
1338 if (!hwnd)
1340 WARN("CreateWindow failed: %ld\n", GetLastError());
1341 CoUninitialize();
1342 FreeLibraryAndExitThread(huia_module, 1);
1345 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_provider_thread_msg_proc);
1346 provider_thread.hwnd = hwnd;
1348 /* Initialization complete, thread can now process window messages. */
1349 SetEvent(initialized_event);
1350 TRACE("Provider thread started.\n");
1351 while (GetMessageW(&msg, NULL, 0, 0))
1353 if (msg.message == WM_UIA_PROVIDER_THREAD_STOP)
1354 break;
1355 TranslateMessage(&msg);
1356 DispatchMessageW(&msg);
1359 TRACE("Shutting down UI Automation provider thread.\n");
1361 DestroyWindow(hwnd);
1362 CoUninitialize();
1363 FreeLibraryAndExitThread(huia_module, 0);
1366 static BOOL uia_start_provider_thread(void)
1368 BOOL started = TRUE;
1370 EnterCriticalSection(&provider_thread_cs);
1371 if (++provider_thread.ref == 1)
1373 HANDLE ready_event;
1374 HANDLE events[2];
1375 HMODULE hmodule;
1376 DWORD wait_obj;
1378 /* Increment DLL reference count. */
1379 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
1380 (const WCHAR *)uia_start_provider_thread, &hmodule);
1382 list_init(&provider_thread.nodes_list);
1383 rb_init(&provider_thread.node_map, uia_runtime_id_compare);
1384 events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1385 if (!(provider_thread.hthread = CreateThread(NULL, 0, uia_provider_thread_proc,
1386 ready_event, 0, NULL)))
1388 FreeLibrary(hmodule);
1389 started = FALSE;
1390 goto exit;
1393 events[1] = provider_thread.hthread;
1394 wait_obj = WaitForMultipleObjects(2, events, FALSE, INFINITE);
1395 if (wait_obj != WAIT_OBJECT_0)
1397 CloseHandle(provider_thread.hthread);
1398 started = FALSE;
1401 exit:
1402 CloseHandle(ready_event);
1403 if (!started)
1405 WARN("Failed to start provider thread\n");
1406 memset(&provider_thread, 0, sizeof(provider_thread));
1410 LeaveCriticalSection(&provider_thread_cs);
1411 return started;
1414 void uia_stop_provider_thread(void)
1416 EnterCriticalSection(&provider_thread_cs);
1417 if (!--provider_thread.ref)
1419 PostMessageW(provider_thread.hwnd, WM_UIA_PROVIDER_THREAD_STOP, 0, 0);
1420 CloseHandle(provider_thread.hthread);
1421 if (!list_empty(&provider_thread.nodes_list))
1422 ERR("Provider thread shutdown with nodes still in the list\n");
1423 memset(&provider_thread, 0, sizeof(provider_thread));
1425 LeaveCriticalSection(&provider_thread_cs);
1429 * Pass our IWineUiaNode interface to the provider thread for marshaling. UI
1430 * Automation has to work regardless of whether or not COM is initialized on
1431 * the thread calling UiaReturnRawElementProvider.
1433 LRESULT uia_lresult_from_node(HUIANODE huianode)
1435 if (!uia_start_provider_thread())
1437 UiaNodeRelease(huianode);
1438 return 0;
1441 return SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode);
1444 /***********************************************************************
1445 * UiaReturnRawElementProvider (uiautomationcore.@)
1447 LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wparam,
1448 LPARAM lparam, IRawElementProviderSimple *elprov)
1450 HUIANODE node;
1451 HRESULT hr;
1453 TRACE("(%p, %Ix, %#Ix, %p)\n", hwnd, wparam, lparam, elprov);
1455 if (!wparam && !lparam && !elprov)
1457 FIXME("UIA-to-MSAA bridge not implemented, no provider map to free.\n");
1458 return 0;
1461 if (lparam != UiaRootObjectId)
1463 FIXME("Unsupported object id %Id, ignoring.\n", lparam);
1464 return 0;
1467 hr = create_uia_node_from_elprov(elprov, &node, FALSE);
1468 if (FAILED(hr))
1470 WARN("Failed to create HUIANODE with hr %#lx\n", hr);
1471 return 0;
1474 return uia_lresult_from_node(node);
1477 /***********************************************************************
1478 * UiaDisconnectProvider (uiautomationcore.@)
1480 HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov)
1482 SAFEARRAY *sa;
1483 HUIANODE node;
1484 HRESULT hr;
1486 TRACE("(%p)\n", elprov);
1488 hr = create_uia_node_from_elprov(elprov, &node, FALSE);
1489 if (FAILED(hr))
1490 return hr;
1492 hr = UiaGetRuntimeId(node, &sa);
1493 UiaNodeRelease(node);
1494 if (FAILED(hr))
1495 return hr;
1497 if (!sa)
1498 return E_INVALIDARG;
1500 uia_provider_thread_disconnect_node(sa);
1502 SafeArrayDestroy(sa);
1504 return S_OK;