uiautomationcore: Implement UiaDisconnectProvider.
[wine.git] / dlls / uiautomationcore / uia_provider.c
blob76eea75f855826ae6671bf9867bf8ad0a0c9691a
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 "initguid.h"
25 #include "wine/iaccessible2.h"
27 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
29 DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
31 static void variant_init_i4(VARIANT *v, int val)
33 V_VT(v) = VT_I4;
34 V_I4(v) = val;
37 static void variant_init_bool(VARIANT *v, BOOL val)
39 V_VT(v) = VT_BOOL;
40 V_BOOL(v) = val ? VARIANT_TRUE : VARIANT_FALSE;
43 static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
45 HRESULT hr;
46 VARIANT v;
48 VariantInit(&v);
49 hr = IAccessible_get_accState(acc, cid, &v);
50 if (SUCCEEDED(hr) && V_VT(&v) == VT_I4 && (V_I4(&v) & flag))
51 return TRUE;
53 return FALSE;
56 static IAccessible2 *msaa_acc_get_ia2(IAccessible *acc)
58 IServiceProvider *serv_prov;
59 IAccessible2 *ia2 = NULL;
60 HRESULT hr;
62 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
63 if (SUCCEEDED(hr))
65 hr = IServiceProvider_QueryService(serv_prov, &IID_IAccessible2, &IID_IAccessible2, (void **)&ia2);
66 IServiceProvider_Release(serv_prov);
67 if (SUCCEEDED(hr) && ia2)
68 return ia2;
71 hr = IAccessible_QueryInterface(acc, &IID_IAccessible2, (void **)&ia2);
72 if (SUCCEEDED(hr) && ia2)
73 return ia2;
75 return NULL;
78 static IAccessible *msaa_acc_da_unwrap(IAccessible *acc)
80 IServiceProvider *sp;
81 IAccessible *acc2;
82 HRESULT hr;
84 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void**)&sp);
85 if (SUCCEEDED(hr))
87 hr = IServiceProvider_QueryService(sp, &SID_AccFromDAWrapper, &IID_IAccessible, (void**)&acc2);
88 IServiceProvider_Release(sp);
91 if (SUCCEEDED(hr) && acc2)
92 return acc2;
94 IAccessible_AddRef(acc);
95 return acc;
99 * Compare role, state, child count, and location properties of the two
100 * IAccessibles. If all four are successfully retrieved and are equal, this is
101 * considered a match.
103 static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2)
105 BOOL role_match, state_match, child_count_match, location_match;
106 LONG child_count[2], left[2], top[2], width[2], height[2];
107 VARIANT cid, v, v2;
108 HRESULT hr, hr2;
110 role_match = state_match = child_count_match = location_match = FALSE;
111 variant_init_i4(&cid, CHILDID_SELF);
112 hr = IAccessible_get_accRole(acc, cid, &v);
113 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
115 VariantInit(&v2);
116 hr = IAccessible_get_accRole(acc2, cid, &v2);
117 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
119 if (V_I4(&v) != V_I4(&v2))
120 return E_FAIL;
122 role_match = TRUE;
126 VariantInit(&v);
127 hr = IAccessible_get_accState(acc, cid, &v);
128 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
130 VariantInit(&v2);
131 hr = IAccessible_get_accState(acc2, cid, &v2);
132 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
134 if (V_I4(&v) != V_I4(&v2))
135 return E_FAIL;
137 state_match = TRUE;
141 hr = IAccessible_get_accChildCount(acc, &child_count[0]);
142 hr2 = IAccessible_get_accChildCount(acc2, &child_count[1]);
143 if (SUCCEEDED(hr) && SUCCEEDED(hr2))
145 if (child_count[0] != child_count[1])
146 return E_FAIL;
148 child_count_match = TRUE;
151 hr = IAccessible_accLocation(acc, &left[0], &top[0], &width[0], &height[0], cid);
152 if (SUCCEEDED(hr))
154 hr = IAccessible_accLocation(acc2, &left[1], &top[1], &width[1], &height[1], cid);
155 if (SUCCEEDED(hr))
157 if ((left[0] != left[1]) || (top[0] != top[1]) || (width[0] != width[1]) ||
158 (height[0] != height[1]))
159 return E_FAIL;
161 location_match = TRUE;
165 if (role_match && state_match && child_count_match && location_match)
166 return S_OK;
168 return S_FALSE;
171 static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
173 IAccessible2 *ia2[2] = { NULL, NULL };
174 IUnknown *unk, *unk2;
175 BOOL matched = FALSE;
176 LONG unique_id[2];
177 BSTR name[2];
178 VARIANT cid;
179 HRESULT hr;
181 acc = msaa_acc_da_unwrap(acc);
182 acc2 = msaa_acc_da_unwrap(acc2);
183 IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk);
184 IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2);
185 if (unk == unk2)
187 matched = TRUE;
188 goto exit;
191 ia2[0] = msaa_acc_get_ia2(acc);
192 ia2[1] = msaa_acc_get_ia2(acc2);
193 if (!ia2[0] != !ia2[1])
194 goto exit;
195 if (ia2[0])
197 hr = IAccessible2_get_uniqueID(ia2[0], &unique_id[0]);
198 if (SUCCEEDED(hr))
200 hr = IAccessible2_get_uniqueID(ia2[1], &unique_id[1]);
201 if (SUCCEEDED(hr))
203 if (unique_id[0] == unique_id[1])
204 matched = TRUE;
206 goto exit;
211 hr = msaa_acc_prop_match(acc, acc2);
212 if (FAILED(hr))
213 goto exit;
214 if (hr == S_OK)
215 matched = TRUE;
217 variant_init_i4(&cid, CHILDID_SELF);
218 hr = IAccessible_get_accName(acc, cid, &name[0]);
219 if (SUCCEEDED(hr))
221 hr = IAccessible_get_accName(acc2, cid, &name[1]);
222 if (SUCCEEDED(hr))
224 if (!name[0] && !name[1])
225 matched = TRUE;
226 else if (!name[0] || !name[1])
227 matched = FALSE;
228 else
230 if (!wcscmp(name[0], name[1]))
231 matched = TRUE;
232 else
233 matched = FALSE;
236 SysFreeString(name[1]);
239 SysFreeString(name[0]);
242 exit:
243 IUnknown_Release(unk);
244 IUnknown_Release(unk2);
245 IAccessible_Release(acc);
246 IAccessible_Release(acc2);
247 if (ia2[0])
248 IAccessible2_Release(ia2[0]);
249 if (ia2[1])
250 IAccessible2_Release(ia2[1]);
252 return matched;
255 static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent)
257 IDispatch *disp = NULL;
258 HRESULT hr;
260 *parent = NULL;
261 hr = IAccessible_get_accParent(acc, &disp);
262 if (FAILED(hr) || !disp)
263 return hr;
265 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void**)parent);
266 IDispatch_Release(disp);
267 return hr;
270 #define DIR_FORWARD 0
271 #define DIR_REVERSE 1
272 static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction,
273 IAccessible **child, LONG *child_id, LONG *child_pos, BOOL check_visible)
275 LONG child_count, cur_pos;
276 IDispatch *disp;
277 VARIANT cid;
278 HRESULT hr;
280 *child = NULL;
281 *child_id = 0;
282 cur_pos = start_pos;
283 while (1)
285 hr = IAccessible_get_accChildCount(acc, &child_count);
286 if (FAILED(hr) || (cur_pos > child_count))
287 break;
289 variant_init_i4(&cid, cur_pos);
290 hr = IAccessible_get_accChild(acc, cid, &disp);
291 if (FAILED(hr))
292 break;
294 if (hr == S_FALSE)
296 if (!check_visible || !msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE))
298 *child = acc;
299 *child_id = *child_pos = cur_pos;
300 IAccessible_AddRef(acc);
301 return S_OK;
304 else
306 IAccessible *acc_child = NULL;
308 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)&acc_child);
309 IDispatch_Release(disp);
310 if (FAILED(hr))
311 break;
313 variant_init_i4(&cid, CHILDID_SELF);
314 if (!check_visible || !msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE))
316 *child = acc_child;
317 *child_id = CHILDID_SELF;
318 *child_pos = cur_pos;
319 return S_OK;
322 IAccessible_Release(acc_child);
325 if (direction == DIR_FORWARD)
326 cur_pos++;
327 else
328 cur_pos--;
330 if ((cur_pos > child_count) || (cur_pos <= 0))
331 break;
334 return hr;
337 static HRESULT msaa_acc_get_child_pos(IAccessible *acc, IAccessible **out_parent,
338 LONG *out_child_pos)
340 LONG child_count, child_id, child_pos, match_pos;
341 IAccessible *child, *parent, *match, **children;
342 HRESULT hr;
343 int i;
345 *out_parent = NULL;
346 *out_child_pos = 0;
347 hr = msaa_acc_get_parent(acc, &parent);
348 if (FAILED(hr) || !parent)
349 return hr;
351 hr = IAccessible_get_accChildCount(parent, &child_count);
352 if (FAILED(hr) || !child_count)
354 IAccessible_Release(parent);
355 return hr;
358 children = heap_alloc_zero(sizeof(*children) * child_count);
359 if (!children)
360 return E_OUTOFMEMORY;
362 match = NULL;
363 for (i = 0; i < child_count; i++)
365 hr = msaa_acc_get_next_child(parent, i + 1, DIR_FORWARD, &child, &child_id, &child_pos, FALSE);
366 if (FAILED(hr) || !child)
367 goto exit;
369 if (child != parent)
370 children[i] = child;
371 else
372 IAccessible_Release(child);
375 for (i = 0; i < child_count; i++)
377 if (!children[i])
378 continue;
380 if (msaa_acc_compare(acc, children[i]))
382 if (!match)
384 match = children[i];
385 match_pos = i + 1;
387 /* Can't have more than one IAccessible match. */
388 else
390 match = NULL;
391 match_pos = 0;
392 break;
397 exit:
398 if (match)
400 *out_parent = parent;
401 *out_child_pos = match_pos;
403 else
404 IAccessible_Release(parent);
406 for (i = 0; i < child_count; i++)
408 if (children[i])
409 IAccessible_Release(children[i]);
412 heap_free(children);
414 return hr;
417 static LONG msaa_role_to_uia_control_type(LONG role)
419 switch (role)
421 case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId;
422 case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId;
423 case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId;
424 case ROLE_SYSTEM_INDICATOR:
425 case ROLE_SYSTEM_GRIP: return UIA_ThumbControlTypeId;
426 case ROLE_SYSTEM_APPLICATION:
427 case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId;
428 case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId;
429 case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId;
430 case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId;
431 case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId;
432 case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId;
433 case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId;
434 case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId;
435 case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId;
436 case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId;
437 case ROLE_SYSTEM_COLUMNHEADER:
438 case ROLE_SYSTEM_ROWHEADER: return UIA_HeaderControlTypeId;
439 case ROLE_SYSTEM_CELL: return UIA_DataItemControlTypeId;
440 case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId;
441 case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId;
442 case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId;
443 case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId;
444 case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId;
445 case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId;
446 case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId;
447 case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId;
448 case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId;
449 case ROLE_SYSTEM_CLOCK:
450 case ROLE_SYSTEM_BUTTONDROPDOWNGRID:
451 case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId;
452 case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId;
453 case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId;
454 case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId;
455 case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId;
456 case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId;
457 case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId;
458 case ROLE_SYSTEM_BUTTONMENU:
459 case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId;
460 case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId;
461 case ROLE_SYSTEM_BUTTONDROPDOWN:
462 case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId;
463 case ROLE_SYSTEM_SOUND:
464 case ROLE_SYSTEM_CURSOR:
465 case ROLE_SYSTEM_CARET:
466 case ROLE_SYSTEM_ALERT:
467 case ROLE_SYSTEM_CLIENT:
468 case ROLE_SYSTEM_CHART:
469 case ROLE_SYSTEM_DIALOG:
470 case ROLE_SYSTEM_BORDER:
471 case ROLE_SYSTEM_COLUMN:
472 case ROLE_SYSTEM_ROW:
473 case ROLE_SYSTEM_HELPBALLOON:
474 case ROLE_SYSTEM_CHARACTER:
475 case ROLE_SYSTEM_PROPERTYPAGE:
476 case ROLE_SYSTEM_DROPLIST:
477 case ROLE_SYSTEM_DIAL:
478 case ROLE_SYSTEM_HOTKEYFIELD:
479 case ROLE_SYSTEM_DIAGRAM:
480 case ROLE_SYSTEM_ANIMATION:
481 case ROLE_SYSTEM_EQUATION:
482 case ROLE_SYSTEM_WHITESPACE:
483 case ROLE_SYSTEM_IPADDRESS:
484 case ROLE_SYSTEM_OUTLINEBUTTON:
485 WARN("No UIA control type mapping for MSAA role %ld\n", role);
486 break;
488 default:
489 FIXME("UIA control type mapping unimplemented for MSAA role %ld\n", role);
490 break;
493 return 0;
497 * UiaProviderFromIAccessible IRawElementProviderSimple interface.
499 struct msaa_provider {
500 IRawElementProviderSimple IRawElementProviderSimple_iface;
501 IRawElementProviderFragment IRawElementProviderFragment_iface;
502 ILegacyIAccessibleProvider ILegacyIAccessibleProvider_iface;
503 LONG refcount;
505 IAccessible *acc;
506 IAccessible2 *ia2;
507 VARIANT cid;
508 HWND hwnd;
509 LONG control_type;
511 BOOL root_acc_check_ran;
512 BOOL is_root_acc;
514 IAccessible *parent;
515 INT child_pos;
518 static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov)
520 IAccessible *acc;
521 HRESULT hr;
523 if (msaa_prov->root_acc_check_ran)
524 return msaa_prov->is_root_acc;
526 msaa_prov->root_acc_check_ran = TRUE;
527 if (V_I4(&msaa_prov->cid) != CHILDID_SELF || msaa_prov->parent)
528 return FALSE;
530 hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
531 if (FAILED(hr))
532 return FALSE;
534 if (msaa_acc_compare(msaa_prov->acc, acc))
535 msaa_prov->is_root_acc = TRUE;
537 IAccessible_Release(acc);
538 return msaa_prov->is_root_acc;
541 static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
543 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
546 HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
548 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
550 *ppv = NULL;
551 if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
552 *ppv = iface;
553 else if (IsEqualIID(riid, &IID_IRawElementProviderFragment))
554 *ppv = &msaa_prov->IRawElementProviderFragment_iface;
555 else if (IsEqualIID(riid, &IID_ILegacyIAccessibleProvider))
556 *ppv = &msaa_prov->ILegacyIAccessibleProvider_iface;
557 else
558 return E_NOINTERFACE;
560 IRawElementProviderSimple_AddRef(iface);
561 return S_OK;
564 ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface)
566 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
567 ULONG refcount = InterlockedIncrement(&msaa_prov->refcount);
569 TRACE("%p, refcount %ld\n", iface, refcount);
571 return refcount;
574 ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
576 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
577 ULONG refcount = InterlockedDecrement(&msaa_prov->refcount);
579 TRACE("%p, refcount %ld\n", iface, refcount);
581 if (!refcount)
583 IAccessible_Release(msaa_prov->acc);
584 if (msaa_prov->parent)
585 IAccessible_Release(msaa_prov->parent);
586 if (msaa_prov->ia2)
587 IAccessible2_Release(msaa_prov->ia2);
588 heap_free(msaa_prov);
591 return refcount;
594 HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
595 enum ProviderOptions *ret_val)
597 TRACE("%p, %p\n", iface, ret_val);
598 *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading;
599 return S_OK;
602 HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface,
603 PATTERNID pattern_id, IUnknown **ret_val)
605 TRACE("%p, %d, %p\n", iface, pattern_id, ret_val);
607 *ret_val = NULL;
608 switch (pattern_id)
610 case UIA_LegacyIAccessiblePatternId:
611 return IRawElementProviderSimple_QueryInterface(iface, &IID_IUnknown, (void **)ret_val);
613 default:
614 FIXME("Unimplemented patternId %d\n", pattern_id);
615 break;
618 return S_OK;
621 HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
622 PROPERTYID prop_id, VARIANT *ret_val)
624 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
625 HRESULT hr;
626 VARIANT v;
628 TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
630 VariantInit(ret_val);
631 VariantInit(&v);
632 switch (prop_id)
634 case UIA_ProviderDescriptionPropertyId:
635 V_VT(ret_val) = VT_BSTR;
636 V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
637 break;
639 case UIA_ControlTypePropertyId:
640 if (!msaa_prov->control_type)
642 hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
643 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
644 msaa_prov->control_type = msaa_role_to_uia_control_type(V_I4(&v));
647 if (msaa_prov->control_type)
648 variant_init_i4(ret_val, msaa_prov->control_type);
650 break;
652 case UIA_HasKeyboardFocusPropertyId:
653 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
654 STATE_SYSTEM_FOCUSED));
655 break;
657 case UIA_IsKeyboardFocusablePropertyId:
658 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
659 STATE_SYSTEM_FOCUSABLE));
660 break;
662 case UIA_IsEnabledPropertyId:
663 variant_init_bool(ret_val, !msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
664 STATE_SYSTEM_UNAVAILABLE));
665 break;
667 case UIA_IsPasswordPropertyId:
668 variant_init_bool(ret_val, msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid,
669 STATE_SYSTEM_PROTECTED));
670 break;
672 default:
673 FIXME("Unimplemented propertyId %d\n", prop_id);
674 break;
677 return S_OK;
680 HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
681 IRawElementProviderSimple **ret_val)
683 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
685 TRACE("%p, %p\n", iface, ret_val);
687 *ret_val = NULL;
688 if (msaa_check_root_acc(msaa_prov))
689 return UiaHostProviderFromHwnd(msaa_prov->hwnd, ret_val);
691 return S_OK;
694 static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
695 msaa_provider_QueryInterface,
696 msaa_provider_AddRef,
697 msaa_provider_Release,
698 msaa_provider_get_ProviderOptions,
699 msaa_provider_GetPatternProvider,
700 msaa_provider_GetPropertyValue,
701 msaa_provider_get_HostRawElementProvider,
705 * IRawElementProviderFragment interface for UiaProviderFromIAccessible
706 * providers.
708 static inline struct msaa_provider *impl_from_msaa_fragment(IRawElementProviderFragment *iface)
710 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderFragment_iface);
713 static HRESULT WINAPI msaa_fragment_QueryInterface(IRawElementProviderFragment *iface, REFIID riid,
714 void **ppv)
716 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
717 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
720 static ULONG WINAPI msaa_fragment_AddRef(IRawElementProviderFragment *iface)
722 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
723 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
726 static ULONG WINAPI msaa_fragment_Release(IRawElementProviderFragment *iface)
728 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
729 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
732 static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
733 enum NavigateDirection direction, IRawElementProviderFragment **ret_val)
735 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
736 LONG child_count, child_id, child_pos;
737 IRawElementProviderSimple *elprov;
738 IAccessible *acc;
739 HRESULT hr;
741 TRACE("%p, %d, %p\n", iface, direction, ret_val);
743 *ret_val = NULL;
744 switch (direction)
746 case NavigateDirection_Parent:
747 if (msaa_check_root_acc(msaa_prov))
748 break;
750 if (V_I4(&msaa_prov->cid) == CHILDID_SELF)
752 hr = msaa_acc_get_parent(msaa_prov->acc, &acc);
753 if (FAILED(hr) || !acc)
754 break;
756 else
757 acc = msaa_prov->acc;
759 hr = UiaProviderFromIAccessible(acc, CHILDID_SELF, 0, &elprov);
760 if (SUCCEEDED(hr))
762 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
763 *ret_val = &prov->IRawElementProviderFragment_iface;
766 if (acc != msaa_prov->acc)
767 IAccessible_Release(acc);
769 break;
771 case NavigateDirection_FirstChild:
772 case NavigateDirection_LastChild:
773 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
774 break;
776 hr = IAccessible_get_accChildCount(msaa_prov->acc, &child_count);
777 if (FAILED(hr) || !child_count)
778 break;
780 if (direction == NavigateDirection_FirstChild)
781 hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id,
782 &child_pos, TRUE);
783 else
784 hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id,
785 &child_pos, TRUE);
787 if (FAILED(hr) || !acc)
788 break;
790 hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
791 if (SUCCEEDED(hr))
793 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
795 *ret_val = &prov->IRawElementProviderFragment_iface;
796 prov->parent = msaa_prov->acc;
797 IAccessible_AddRef(msaa_prov->acc);
798 if (acc != msaa_prov->acc)
799 prov->child_pos = child_pos;
800 else
801 prov->child_pos = child_id;
803 IAccessible_Release(acc);
805 break;
807 case NavigateDirection_NextSibling:
808 case NavigateDirection_PreviousSibling:
809 if (msaa_check_root_acc(msaa_prov))
810 break;
812 if (!msaa_prov->parent)
814 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
816 msaa_prov->parent = msaa_prov->acc;
817 IAccessible_AddRef(msaa_prov->acc);
818 msaa_prov->child_pos = V_I4(&msaa_prov->cid);
820 else
822 hr = msaa_acc_get_child_pos(msaa_prov->acc, &acc, &child_pos);
823 if (FAILED(hr) || !acc)
824 break;
825 msaa_prov->parent = acc;
826 msaa_prov->child_pos = child_pos;
830 if (direction == NavigateDirection_NextSibling)
831 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos + 1, DIR_FORWARD,
832 &acc, &child_id, &child_pos, TRUE);
833 else
834 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos - 1, DIR_REVERSE,
835 &acc, &child_id, &child_pos, TRUE);
837 if (FAILED(hr) || !acc)
838 break;
840 hr = UiaProviderFromIAccessible(acc, child_id, 0, &elprov);
841 if (SUCCEEDED(hr))
843 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
845 *ret_val = &prov->IRawElementProviderFragment_iface;
846 prov->parent = msaa_prov->parent;
847 IAccessible_AddRef(msaa_prov->parent);
848 if (acc != msaa_prov->acc)
849 prov->child_pos = child_pos;
850 else
851 prov->child_pos = child_id;
853 IAccessible_Release(acc);
855 break;
857 default:
858 FIXME("Invalid NavigateDirection %d\n", direction);
859 return E_INVALIDARG;
862 return S_OK;
865 static HRESULT WINAPI msaa_fragment_GetRuntimeId(IRawElementProviderFragment *iface,
866 SAFEARRAY **ret_val)
868 FIXME("%p, %p: stub!\n", iface, ret_val);
869 *ret_val = NULL;
870 return E_NOTIMPL;
873 static HRESULT WINAPI msaa_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface,
874 struct UiaRect *ret_val)
876 FIXME("%p, %p: stub!\n", iface, ret_val);
877 return E_NOTIMPL;
880 static HRESULT WINAPI msaa_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface,
881 SAFEARRAY **ret_val)
883 FIXME("%p, %p: stub!\n", iface, ret_val);
884 *ret_val = NULL;
885 return E_NOTIMPL;
888 static HRESULT WINAPI msaa_fragment_SetFocus(IRawElementProviderFragment *iface)
890 FIXME("%p: stub!\n", iface);
891 return E_NOTIMPL;
894 static HRESULT WINAPI msaa_fragment_get_FragmentRoot(IRawElementProviderFragment *iface,
895 IRawElementProviderFragmentRoot **ret_val)
897 FIXME("%p, %p: stub!\n", iface, ret_val);
898 *ret_val = NULL;
899 return E_NOTIMPL;
902 static const IRawElementProviderFragmentVtbl msaa_fragment_vtbl = {
903 msaa_fragment_QueryInterface,
904 msaa_fragment_AddRef,
905 msaa_fragment_Release,
906 msaa_fragment_Navigate,
907 msaa_fragment_GetRuntimeId,
908 msaa_fragment_get_BoundingRectangle,
909 msaa_fragment_GetEmbeddedFragmentRoots,
910 msaa_fragment_SetFocus,
911 msaa_fragment_get_FragmentRoot,
915 * ILegacyIAccessibleProvider interface for UiaProviderFromIAccessible
916 * providers.
918 static inline struct msaa_provider *impl_from_msaa_acc_provider(ILegacyIAccessibleProvider *iface)
920 return CONTAINING_RECORD(iface, struct msaa_provider, ILegacyIAccessibleProvider_iface);
923 static HRESULT WINAPI msaa_acc_provider_QueryInterface(ILegacyIAccessibleProvider *iface, REFIID riid, void **ppv)
925 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
926 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
929 static ULONG WINAPI msaa_acc_provider_AddRef(ILegacyIAccessibleProvider *iface)
931 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
932 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
935 static ULONG WINAPI msaa_acc_provider_Release(ILegacyIAccessibleProvider *iface)
937 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
938 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
941 static HRESULT WINAPI msaa_acc_provider_Select(ILegacyIAccessibleProvider *iface, LONG select_flags)
943 FIXME("%p, %#lx: stub!\n", iface, select_flags);
944 return E_NOTIMPL;
947 static HRESULT WINAPI msaa_acc_provider_DoDefaultAction(ILegacyIAccessibleProvider *iface)
949 FIXME("%p: stub!\n", iface);
950 return E_NOTIMPL;
953 static HRESULT WINAPI msaa_acc_provider_SetValue(ILegacyIAccessibleProvider *iface, LPCWSTR val)
955 FIXME("%p, %p<%s>: stub!\n", iface, val, debugstr_w(val));
956 return E_NOTIMPL;
959 static HRESULT WINAPI msaa_acc_provider_GetIAccessible(ILegacyIAccessibleProvider *iface,
960 IAccessible **out_acc)
962 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
964 TRACE("%p, %p\n", iface, out_acc);
966 IAccessible_AddRef(msaa_prov->acc);
967 *out_acc = msaa_prov->acc;
969 return S_OK;
972 static HRESULT WINAPI msaa_acc_provider_get_ChildId(ILegacyIAccessibleProvider *iface, int *out_cid)
974 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
976 TRACE("%p, %p\n", iface, out_cid);
977 *out_cid = V_I4(&msaa_prov->cid);
979 return S_OK;
982 static HRESULT WINAPI msaa_acc_provider_get_Name(ILegacyIAccessibleProvider *iface, BSTR *out_name)
984 FIXME("%p, %p: stub!\n", iface, out_name);
985 return E_NOTIMPL;
988 static HRESULT WINAPI msaa_acc_provider_get_Value(ILegacyIAccessibleProvider *iface, BSTR *out_value)
990 FIXME("%p, %p: stub!\n", iface, out_value);
991 return E_NOTIMPL;
994 static HRESULT WINAPI msaa_acc_provider_get_Description(ILegacyIAccessibleProvider *iface,
995 BSTR *out_description)
997 FIXME("%p, %p: stub!\n", iface, out_description);
998 return E_NOTIMPL;
1001 static HRESULT WINAPI msaa_acc_provider_get_Role(ILegacyIAccessibleProvider *iface, DWORD *out_role)
1003 FIXME("%p, %p: stub!\n", iface, out_role);
1004 return E_NOTIMPL;
1007 static HRESULT WINAPI msaa_acc_provider_get_State(ILegacyIAccessibleProvider *iface, DWORD *out_state)
1009 FIXME("%p, %p: stub!\n", iface, out_state);
1010 return E_NOTIMPL;
1013 static HRESULT WINAPI msaa_acc_provider_get_Help(ILegacyIAccessibleProvider *iface, BSTR *out_help)
1015 FIXME("%p, %p: stub!\n", iface, out_help);
1016 return E_NOTIMPL;
1019 static HRESULT WINAPI msaa_acc_provider_get_KeyboardShortcut(ILegacyIAccessibleProvider *iface,
1020 BSTR *out_kbd_shortcut)
1022 FIXME("%p, %p: stub!\n", iface, out_kbd_shortcut);
1023 return E_NOTIMPL;
1026 static HRESULT WINAPI msaa_acc_provider_GetSelection(ILegacyIAccessibleProvider *iface,
1027 SAFEARRAY **out_selected)
1029 FIXME("%p, %p: stub!\n", iface, out_selected);
1030 return E_NOTIMPL;
1033 static HRESULT WINAPI msaa_acc_provider_get_DefaultAction(ILegacyIAccessibleProvider *iface,
1034 BSTR *out_default_action)
1036 FIXME("%p, %p: stub!\n", iface, out_default_action);
1037 return E_NOTIMPL;
1040 static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = {
1041 msaa_acc_provider_QueryInterface,
1042 msaa_acc_provider_AddRef,
1043 msaa_acc_provider_Release,
1044 msaa_acc_provider_Select,
1045 msaa_acc_provider_DoDefaultAction,
1046 msaa_acc_provider_SetValue,
1047 msaa_acc_provider_GetIAccessible,
1048 msaa_acc_provider_get_ChildId,
1049 msaa_acc_provider_get_Name,
1050 msaa_acc_provider_get_Value,
1051 msaa_acc_provider_get_Description,
1052 msaa_acc_provider_get_Role,
1053 msaa_acc_provider_get_State,
1054 msaa_acc_provider_get_Help,
1055 msaa_acc_provider_get_KeyboardShortcut,
1056 msaa_acc_provider_GetSelection,
1057 msaa_acc_provider_get_DefaultAction,
1060 /***********************************************************************
1061 * UiaProviderFromIAccessible (uiautomationcore.@)
1063 HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, long child_id, DWORD flags,
1064 IRawElementProviderSimple **elprov)
1066 struct msaa_provider *msaa_prov;
1067 IServiceProvider *serv_prov;
1068 HWND hwnd = NULL;
1069 HRESULT hr;
1071 TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
1073 if (elprov)
1074 *elprov = NULL;
1076 if (!elprov)
1077 return E_POINTER;
1078 if (!acc)
1079 return E_INVALIDARG;
1081 if (flags != UIA_PFIA_DEFAULT)
1083 FIXME("unsupported flags %#lx\n", flags);
1084 return E_NOTIMPL;
1087 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&serv_prov);
1088 if (SUCCEEDED(hr))
1090 IUnknown *unk;
1092 hr = IServiceProvider_QueryService(serv_prov, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk);
1093 if (SUCCEEDED(hr))
1095 WARN("Cannot wrap an oleacc proxy IAccessible!\n");
1096 IUnknown_Release(unk);
1097 IServiceProvider_Release(serv_prov);
1098 return E_INVALIDARG;
1101 IServiceProvider_Release(serv_prov);
1104 hr = WindowFromAccessibleObject(acc, &hwnd);
1105 if (FAILED(hr))
1106 return hr;
1107 if (!hwnd)
1108 return E_FAIL;
1110 msaa_prov = heap_alloc_zero(sizeof(*msaa_prov));
1111 if (!msaa_prov)
1112 return E_OUTOFMEMORY;
1114 msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
1115 msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
1116 msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
1117 msaa_prov->refcount = 1;
1118 msaa_prov->hwnd = hwnd;
1119 variant_init_i4(&msaa_prov->cid, child_id);
1120 msaa_prov->acc = acc;
1121 IAccessible_AddRef(acc);
1122 msaa_prov->ia2 = msaa_acc_get_ia2(acc);
1123 *elprov = &msaa_prov->IRawElementProviderSimple_iface;
1125 return S_OK;
1129 * UI Automation provider thread functions.
1131 struct uia_provider_thread
1133 struct list nodes_list;
1134 HANDLE hthread;
1135 HWND hwnd;
1136 LONG ref;
1139 static struct uia_provider_thread provider_thread;
1140 static CRITICAL_SECTION provider_thread_cs;
1141 static CRITICAL_SECTION_DEBUG provider_thread_cs_debug =
1143 0, 0, &provider_thread_cs,
1144 { &provider_thread_cs_debug.ProcessLocksList, &provider_thread_cs_debug.ProcessLocksList },
1145 0, 0, { (DWORD_PTR)(__FILE__ ": provider_thread_cs") }
1147 static CRITICAL_SECTION provider_thread_cs = { &provider_thread_cs_debug, -1, 0, 0, 0, 0 };
1149 void uia_provider_thread_remove_node(HUIANODE node)
1151 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1153 TRACE("Removing node %p\n", node);
1155 EnterCriticalSection(&provider_thread_cs);
1156 list_remove(&node_data->prov_thread_list_entry);
1157 list_init(&node_data->prov_thread_list_entry);
1158 SafeArrayDestroy(node_data->runtime_id);
1159 node_data->runtime_id = NULL;
1160 LeaveCriticalSection(&provider_thread_cs);
1163 static void uia_provider_thread_disconnect_node(SAFEARRAY *sa)
1165 struct list *cursor, *cursor2;
1166 struct uia_node *node_data;
1168 EnterCriticalSection(&provider_thread_cs);
1170 /* Provider thread hasn't been started, no nodes to disconnect. */
1171 if (!provider_thread.ref)
1172 goto exit;
1174 LIST_FOR_EACH_SAFE(cursor, cursor2, &provider_thread.nodes_list)
1176 node_data = LIST_ENTRY(cursor, struct uia_node, prov_thread_list_entry);
1178 if (node_data->runtime_id)
1180 if (!uia_compare_runtime_ids(sa, node_data->runtime_id))
1182 list_remove(cursor);
1183 list_init(&node_data->prov_thread_list_entry);
1184 IWineUiaNode_disconnect(&node_data->IWineUiaNode_iface);
1185 SafeArrayDestroy(node_data->runtime_id);
1186 node_data->runtime_id = NULL;
1191 exit:
1192 LeaveCriticalSection(&provider_thread_cs);
1195 static HRESULT uia_provider_thread_add_node(HUIANODE node)
1197 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1198 SAFEARRAY *sa;
1199 HRESULT hr;
1201 node_data->nested_node = TRUE;
1202 hr = UiaGetRuntimeId(node, &sa);
1203 if (FAILED(hr))
1204 return hr;
1206 TRACE("Adding node %p\n", node);
1208 EnterCriticalSection(&provider_thread_cs);
1209 node_data->runtime_id = sa;
1210 list_add_tail(&provider_thread.nodes_list, &node_data->prov_thread_list_entry);
1211 LeaveCriticalSection(&provider_thread_cs);
1213 return S_OK;
1216 #define WM_GET_OBJECT_UIA_NODE (WM_USER + 1)
1217 #define WM_UIA_PROVIDER_THREAD_STOP (WM_USER + 2)
1218 static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam,
1219 LPARAM lparam)
1221 switch (msg)
1223 case WM_GET_OBJECT_UIA_NODE:
1225 HUIANODE node = (HUIANODE)lparam;
1226 LRESULT lr;
1228 if (FAILED(uia_provider_thread_add_node(node)))
1230 WARN("Failed to add node %p to provider thread list.\n", node);
1231 UiaNodeRelease(node);
1232 return 0;
1236 * LresultFromObject returns an index into the global atom string table,
1237 * which has a valid range of 0xc000-0xffff.
1239 lr = LresultFromObject(&IID_IWineUiaNode, 0, (IUnknown *)node);
1240 if ((lr > 0xffff) || (lr < 0xc000))
1242 WARN("Got invalid lresult %Ix\n", lr);
1243 lr = 0;
1247 * LresultFromObject increases refcnt by 1. If LresultFromObject
1248 * failed, this is expected to release the node.
1250 UiaNodeRelease(node);
1251 return lr;
1254 default:
1255 break;
1258 return DefWindowProcW(hwnd, msg, wparam, lparam);
1261 static DWORD WINAPI uia_provider_thread_proc(void *arg)
1263 HANDLE initialized_event = arg;
1264 HWND hwnd;
1265 MSG msg;
1267 CoInitializeEx(NULL, COINIT_MULTITHREADED);
1268 hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
1269 if (!hwnd)
1271 WARN("CreateWindow failed: %ld\n", GetLastError());
1272 CoUninitialize();
1273 FreeLibraryAndExitThread(huia_module, 1);
1276 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_provider_thread_msg_proc);
1277 provider_thread.hwnd = hwnd;
1279 /* Initialization complete, thread can now process window messages. */
1280 SetEvent(initialized_event);
1281 TRACE("Provider thread started.\n");
1282 while (GetMessageW(&msg, NULL, 0, 0))
1284 if (msg.message == WM_UIA_PROVIDER_THREAD_STOP)
1285 break;
1286 TranslateMessage(&msg);
1287 DispatchMessageW(&msg);
1290 TRACE("Shutting down UI Automation provider thread.\n");
1292 DestroyWindow(hwnd);
1293 CoUninitialize();
1294 FreeLibraryAndExitThread(huia_module, 0);
1297 static BOOL uia_start_provider_thread(void)
1299 BOOL started = TRUE;
1301 EnterCriticalSection(&provider_thread_cs);
1302 if (++provider_thread.ref == 1)
1304 HANDLE ready_event;
1305 HANDLE events[2];
1306 HMODULE hmodule;
1307 DWORD wait_obj;
1309 /* Increment DLL reference count. */
1310 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
1311 (const WCHAR *)uia_start_provider_thread, &hmodule);
1313 list_init(&provider_thread.nodes_list);
1314 events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
1315 if (!(provider_thread.hthread = CreateThread(NULL, 0, uia_provider_thread_proc,
1316 ready_event, 0, NULL)))
1318 FreeLibrary(hmodule);
1319 started = FALSE;
1320 goto exit;
1323 events[1] = provider_thread.hthread;
1324 wait_obj = WaitForMultipleObjects(2, events, FALSE, INFINITE);
1325 if (wait_obj != WAIT_OBJECT_0)
1327 CloseHandle(provider_thread.hthread);
1328 started = FALSE;
1331 exit:
1332 CloseHandle(ready_event);
1333 if (!started)
1335 WARN("Failed to start provider thread\n");
1336 memset(&provider_thread, 0, sizeof(provider_thread));
1340 LeaveCriticalSection(&provider_thread_cs);
1341 return started;
1344 void uia_stop_provider_thread(void)
1346 EnterCriticalSection(&provider_thread_cs);
1347 if (!--provider_thread.ref)
1349 PostMessageW(provider_thread.hwnd, WM_UIA_PROVIDER_THREAD_STOP, 0, 0);
1350 CloseHandle(provider_thread.hthread);
1351 if (!list_empty(&provider_thread.nodes_list))
1352 ERR("Provider thread shutdown with nodes still in the list\n");
1353 memset(&provider_thread, 0, sizeof(provider_thread));
1355 LeaveCriticalSection(&provider_thread_cs);
1359 * Pass our IWineUiaNode interface to the provider thread for marshaling. UI
1360 * Automation has to work regardless of whether or not COM is initialized on
1361 * the thread calling UiaReturnRawElementProvider.
1363 static LRESULT uia_lresult_from_node(HUIANODE huianode)
1365 if (!uia_start_provider_thread())
1367 UiaNodeRelease(huianode);
1368 return 0;
1371 return SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, 0, (LPARAM)huianode);
1374 /***********************************************************************
1375 * UiaReturnRawElementProvider (uiautomationcore.@)
1377 LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wparam,
1378 LPARAM lparam, IRawElementProviderSimple *elprov)
1380 HUIANODE node;
1381 HRESULT hr;
1383 TRACE("(%p, %Ix, %#Ix, %p)\n", hwnd, wparam, lparam, elprov);
1385 if (!wparam && !lparam && !elprov)
1387 FIXME("UIA-to-MSAA bridge not implemented, no provider map to free.\n");
1388 return 0;
1391 if (lparam != UiaRootObjectId)
1393 FIXME("Unsupported object id %Id, ignoring.\n", lparam);
1394 return 0;
1397 hr = UiaNodeFromProvider(elprov, &node);
1398 if (FAILED(hr))
1400 WARN("Failed to create HUIANODE with hr %#lx\n", hr);
1401 return 0;
1404 return uia_lresult_from_node(node);
1407 /***********************************************************************
1408 * UiaDisconnectProvider (uiautomationcore.@)
1410 HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov)
1412 SAFEARRAY *sa;
1413 HUIANODE node;
1414 HRESULT hr;
1416 TRACE("(%p)\n", elprov);
1418 hr = UiaNodeFromProvider(elprov, &node);
1419 if (FAILED(hr))
1420 return hr;
1422 hr = UiaGetRuntimeId(node, &sa);
1423 UiaNodeRelease(node);
1424 if (FAILED(hr))
1425 return hr;
1427 if (!sa)
1428 return E_INVALIDARG;
1430 uia_provider_thread_disconnect_node(sa);
1432 SafeArrayDestroy(sa);
1434 return S_OK;