d3d10/effect: Add support for 'imul' instruction.
[wine.git] / dlls / uiautomationcore / uia_provider.c
blob917d21d8a82cf93e5caa76f6fa5adb618d903f3f
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 "initguid.h"
24 #include "wine/iaccessible2.h"
26 WINE_DEFAULT_DEBUG_CHANNEL(uiautomation);
28 DEFINE_GUID(SID_AccFromDAWrapper, 0x33f139ee, 0xe509, 0x47f7, 0xbf,0x39, 0x83,0x76,0x44,0xf7,0x45,0x76);
30 /* Returns S_OK if flag is set, S_FALSE if it is not. */
31 static HRESULT msaa_check_acc_state_hres(IAccessible *acc, VARIANT cid, ULONG flag)
33 HRESULT hr;
34 VARIANT v;
36 VariantInit(&v);
37 hr = IAccessible_get_accState(acc, cid, &v);
38 if (SUCCEEDED(hr))
39 hr = ((V_VT(&v) == VT_I4) && (V_I4(&v) & flag)) ? S_OK : S_FALSE;
41 return hr;
44 static BOOL msaa_check_acc_state(IAccessible *acc, VARIANT cid, ULONG flag)
46 return msaa_check_acc_state_hres(acc, cid, flag) == S_OK;
49 static HRESULT msaa_acc_get_service(IAccessible *acc, REFGUID sid, REFIID riid, void **service)
51 IServiceProvider *sp;
52 HRESULT hr;
54 *service = NULL;
55 hr = IAccessible_QueryInterface(acc, &IID_IServiceProvider, (void **)&sp);
56 if (FAILED(hr))
57 return hr;
59 hr = IServiceProvider_QueryService(sp, sid, riid, (void **)service);
60 IServiceProvider_Release(sp);
61 return hr;
64 static IAccessible2 *msaa_acc_get_ia2(IAccessible *acc)
66 IAccessible2 *ia2 = NULL;
67 HRESULT hr;
69 hr = msaa_acc_get_service(acc, &IID_IAccessible2, &IID_IAccessible2, (void **)&ia2);
70 if (SUCCEEDED(hr) && ia2)
71 return ia2;
73 hr = IAccessible_QueryInterface(acc, &IID_IAccessible2, (void **)&ia2);
74 if (SUCCEEDED(hr) && ia2)
75 return ia2;
77 return NULL;
80 static IAccessible *msaa_acc_da_unwrap(IAccessible *acc)
82 IAccessible *acc2;
83 HRESULT hr;
85 hr = msaa_acc_get_service(acc, &SID_AccFromDAWrapper, &IID_IAccessible, (void **)&acc2);
86 if (SUCCEEDED(hr) && acc2)
87 return acc2;
89 IAccessible_AddRef(acc);
90 return acc;
93 static BOOL msaa_acc_is_oleacc_proxy(IAccessible *acc)
95 IUnknown *unk;
96 HRESULT hr;
98 hr = msaa_acc_get_service(acc, &IIS_IsOleaccProxy, &IID_IUnknown, (void **)&unk);
99 if (SUCCEEDED(hr) && unk)
101 IUnknown_Release(unk);
102 return TRUE;
105 return FALSE;
109 * Compare role, state, child count, and location properties of the two
110 * IAccessibles. If all four are successfully retrieved and are equal, this is
111 * considered a match.
113 static HRESULT msaa_acc_prop_match(IAccessible *acc, IAccessible *acc2)
115 BOOL role_match, state_match, child_count_match, location_match;
116 LONG child_count[2], left[2], top[2], width[2], height[2];
117 VARIANT cid, v, v2;
118 HRESULT hr, hr2;
120 role_match = state_match = child_count_match = location_match = FALSE;
121 variant_init_i4(&cid, CHILDID_SELF);
122 hr = IAccessible_get_accRole(acc, cid, &v);
123 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
125 VariantInit(&v2);
126 hr = IAccessible_get_accRole(acc2, cid, &v2);
127 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
129 if (V_I4(&v) != V_I4(&v2))
130 return E_FAIL;
132 role_match = TRUE;
136 VariantInit(&v);
137 hr = IAccessible_get_accState(acc, cid, &v);
138 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
140 VariantInit(&v2);
141 hr = IAccessible_get_accState(acc2, cid, &v2);
142 if (SUCCEEDED(hr) && (V_VT(&v2) == VT_I4))
144 if (V_I4(&v) != V_I4(&v2))
145 return E_FAIL;
147 state_match = TRUE;
151 hr = IAccessible_get_accChildCount(acc, &child_count[0]);
152 hr2 = IAccessible_get_accChildCount(acc2, &child_count[1]);
153 if (SUCCEEDED(hr) && SUCCEEDED(hr2))
155 if (child_count[0] != child_count[1])
156 return E_FAIL;
158 child_count_match = TRUE;
161 hr = IAccessible_accLocation(acc, &left[0], &top[0], &width[0], &height[0], cid);
162 if (SUCCEEDED(hr))
164 hr = IAccessible_accLocation(acc2, &left[1], &top[1], &width[1], &height[1], cid);
165 if (SUCCEEDED(hr))
167 if ((left[0] != left[1]) || (top[0] != top[1]) || (width[0] != width[1]) ||
168 (height[0] != height[1]))
169 return E_FAIL;
171 location_match = TRUE;
175 if (role_match && state_match && child_count_match && location_match)
176 return S_OK;
178 return S_FALSE;
181 static BOOL msaa_acc_iface_cmp(IAccessible *acc, IAccessible *acc2)
183 IUnknown *unk, *unk2;
184 BOOL matched;
186 acc = msaa_acc_da_unwrap(acc);
187 acc2 = msaa_acc_da_unwrap(acc2);
188 IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk);
189 IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2);
190 matched = (unk == unk2);
192 IAccessible_Release(acc);
193 IUnknown_Release(unk);
194 IAccessible_Release(acc2);
195 IUnknown_Release(unk2);
197 return matched;
200 static BOOL msaa_acc_compare(IAccessible *acc, IAccessible *acc2)
202 IAccessible2 *ia2[2] = { NULL, NULL };
203 IUnknown *unk, *unk2;
204 BOOL matched = FALSE;
205 LONG unique_id[2];
206 BSTR name[2];
207 VARIANT cid;
208 HRESULT hr;
210 acc = msaa_acc_da_unwrap(acc);
211 acc2 = msaa_acc_da_unwrap(acc2);
212 IAccessible_QueryInterface(acc, &IID_IUnknown, (void**)&unk);
213 IAccessible_QueryInterface(acc2, &IID_IUnknown, (void**)&unk2);
214 if (unk == unk2)
216 matched = TRUE;
217 goto exit;
220 ia2[0] = msaa_acc_get_ia2(acc);
221 ia2[1] = msaa_acc_get_ia2(acc2);
222 if (!ia2[0] != !ia2[1])
223 goto exit;
224 if (ia2[0])
226 hr = IAccessible2_get_uniqueID(ia2[0], &unique_id[0]);
227 if (SUCCEEDED(hr))
229 hr = IAccessible2_get_uniqueID(ia2[1], &unique_id[1]);
230 if (SUCCEEDED(hr))
232 if (unique_id[0] == unique_id[1])
233 matched = TRUE;
235 goto exit;
240 hr = msaa_acc_prop_match(acc, acc2);
241 if (FAILED(hr))
242 goto exit;
243 if (hr == S_OK)
244 matched = TRUE;
246 variant_init_i4(&cid, CHILDID_SELF);
247 hr = IAccessible_get_accName(acc, cid, &name[0]);
248 if (SUCCEEDED(hr))
250 hr = IAccessible_get_accName(acc2, cid, &name[1]);
251 if (SUCCEEDED(hr))
253 if (!name[0] && !name[1])
254 matched = TRUE;
255 else if (!name[0] || !name[1])
256 matched = FALSE;
257 else
259 if (!wcscmp(name[0], name[1]))
260 matched = TRUE;
261 else
262 matched = FALSE;
265 SysFreeString(name[1]);
268 SysFreeString(name[0]);
271 exit:
272 IUnknown_Release(unk);
273 IUnknown_Release(unk2);
274 IAccessible_Release(acc);
275 IAccessible_Release(acc2);
276 if (ia2[0])
277 IAccessible2_Release(ia2[0]);
278 if (ia2[1])
279 IAccessible2_Release(ia2[1]);
281 return matched;
284 static HRESULT msaa_acc_get_parent(IAccessible *acc, IAccessible **parent)
286 IDispatch *disp = NULL;
287 HRESULT hr;
289 *parent = NULL;
290 hr = IAccessible_get_accParent(acc, &disp);
291 if (FAILED(hr) || !disp)
292 return hr;
294 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void**)parent);
295 IDispatch_Release(disp);
296 return hr;
299 #define DIR_FORWARD 0
300 #define DIR_REVERSE 1
301 static HRESULT msaa_acc_get_next_child(IAccessible *acc, LONG start_pos, LONG direction,
302 IAccessible **child, LONG *child_id, LONG *child_pos, BOOL check_visible)
304 LONG child_count, cur_pos;
305 IDispatch *disp;
306 VARIANT cid;
307 HRESULT hr;
309 *child = NULL;
310 *child_id = 0;
311 cur_pos = start_pos;
312 while (1)
314 hr = IAccessible_get_accChildCount(acc, &child_count);
315 if (FAILED(hr) || (cur_pos > child_count))
316 break;
318 variant_init_i4(&cid, cur_pos);
319 hr = IAccessible_get_accChild(acc, cid, &disp);
320 if (FAILED(hr))
321 break;
323 if (hr == S_FALSE)
325 if (!check_visible || !msaa_check_acc_state(acc, cid, STATE_SYSTEM_INVISIBLE))
327 *child = acc;
328 *child_id = *child_pos = cur_pos;
329 IAccessible_AddRef(acc);
330 return S_OK;
333 else
335 IAccessible *acc_child = NULL;
337 hr = IDispatch_QueryInterface(disp, &IID_IAccessible, (void **)&acc_child);
338 IDispatch_Release(disp);
339 if (FAILED(hr))
340 break;
342 variant_init_i4(&cid, CHILDID_SELF);
343 if (!check_visible || !msaa_check_acc_state(acc_child, cid, STATE_SYSTEM_INVISIBLE))
345 *child = acc_child;
346 *child_id = CHILDID_SELF;
347 *child_pos = cur_pos;
348 return S_OK;
351 IAccessible_Release(acc_child);
354 if (direction == DIR_FORWARD)
355 cur_pos++;
356 else
357 cur_pos--;
359 if ((cur_pos > child_count) || (cur_pos <= 0))
360 break;
363 return hr;
366 static HRESULT msaa_acc_get_child_pos(IAccessible *acc, IAccessible **out_parent,
367 LONG *out_child_pos)
369 LONG child_count, child_id, child_pos, match_pos;
370 IAccessible *child, *parent, *match, **children;
371 HRESULT hr;
372 int i;
374 *out_parent = NULL;
375 *out_child_pos = 0;
376 hr = msaa_acc_get_parent(acc, &parent);
377 if (FAILED(hr) || !parent)
378 return hr;
380 hr = IAccessible_get_accChildCount(parent, &child_count);
381 if (FAILED(hr) || !child_count)
383 IAccessible_Release(parent);
384 return hr;
387 children = calloc(child_count, sizeof(*children));
388 if (!children)
389 return E_OUTOFMEMORY;
391 match = NULL;
392 for (i = 0; i < child_count; i++)
394 hr = msaa_acc_get_next_child(parent, i + 1, DIR_FORWARD, &child, &child_id, &child_pos, FALSE);
395 if (FAILED(hr) || !child)
396 goto exit;
398 if (child != parent)
399 children[i] = child;
400 else
401 IAccessible_Release(child);
404 for (i = 0; i < child_count; i++)
406 if (!children[i])
407 continue;
409 if (msaa_acc_compare(acc, children[i]))
411 if (!match)
413 match = children[i];
414 match_pos = i + 1;
416 /* Can't have more than one IAccessible match. */
417 else
419 match = NULL;
420 match_pos = 0;
421 break;
426 exit:
427 if (match)
429 *out_parent = parent;
430 *out_child_pos = match_pos;
432 else
433 IAccessible_Release(parent);
435 for (i = 0; i < child_count; i++)
437 if (children[i])
438 IAccessible_Release(children[i]);
441 free(children);
443 return hr;
446 static LONG msaa_role_to_uia_control_type(LONG role)
448 switch (role)
450 case ROLE_SYSTEM_TITLEBAR: return UIA_TitleBarControlTypeId;
451 case ROLE_SYSTEM_MENUBAR: return UIA_MenuBarControlTypeId;
452 case ROLE_SYSTEM_SCROLLBAR: return UIA_ScrollBarControlTypeId;
453 case ROLE_SYSTEM_INDICATOR:
454 case ROLE_SYSTEM_GRIP: return UIA_ThumbControlTypeId;
455 case ROLE_SYSTEM_APPLICATION:
456 case ROLE_SYSTEM_WINDOW: return UIA_WindowControlTypeId;
457 case ROLE_SYSTEM_MENUPOPUP: return UIA_MenuControlTypeId;
458 case ROLE_SYSTEM_TOOLTIP: return UIA_ToolTipControlTypeId;
459 case ROLE_SYSTEM_DOCUMENT: return UIA_DocumentControlTypeId;
460 case ROLE_SYSTEM_PANE: return UIA_PaneControlTypeId;
461 case ROLE_SYSTEM_GROUPING: return UIA_GroupControlTypeId;
462 case ROLE_SYSTEM_SEPARATOR: return UIA_SeparatorControlTypeId;
463 case ROLE_SYSTEM_TOOLBAR: return UIA_ToolBarControlTypeId;
464 case ROLE_SYSTEM_STATUSBAR: return UIA_StatusBarControlTypeId;
465 case ROLE_SYSTEM_TABLE: return UIA_TableControlTypeId;
466 case ROLE_SYSTEM_COLUMNHEADER:
467 case ROLE_SYSTEM_ROWHEADER: return UIA_HeaderControlTypeId;
468 case ROLE_SYSTEM_CELL: return UIA_DataItemControlTypeId;
469 case ROLE_SYSTEM_LINK: return UIA_HyperlinkControlTypeId;
470 case ROLE_SYSTEM_LIST: return UIA_ListControlTypeId;
471 case ROLE_SYSTEM_LISTITEM: return UIA_ListItemControlTypeId;
472 case ROLE_SYSTEM_OUTLINE: return UIA_TreeControlTypeId;
473 case ROLE_SYSTEM_OUTLINEITEM: return UIA_TreeItemControlTypeId;
474 case ROLE_SYSTEM_PAGETAB: return UIA_TabItemControlTypeId;
475 case ROLE_SYSTEM_GRAPHIC: return UIA_ImageControlTypeId;
476 case ROLE_SYSTEM_STATICTEXT: return UIA_TextControlTypeId;
477 case ROLE_SYSTEM_TEXT: return UIA_EditControlTypeId;
478 case ROLE_SYSTEM_CLOCK:
479 case ROLE_SYSTEM_BUTTONDROPDOWNGRID:
480 case ROLE_SYSTEM_PUSHBUTTON: return UIA_ButtonControlTypeId;
481 case ROLE_SYSTEM_CHECKBUTTON: return UIA_CheckBoxControlTypeId;
482 case ROLE_SYSTEM_RADIOBUTTON: return UIA_RadioButtonControlTypeId;
483 case ROLE_SYSTEM_COMBOBOX: return UIA_ComboBoxControlTypeId;
484 case ROLE_SYSTEM_PROGRESSBAR: return UIA_ProgressBarControlTypeId;
485 case ROLE_SYSTEM_SLIDER: return UIA_SliderControlTypeId;
486 case ROLE_SYSTEM_SPINBUTTON: return UIA_SpinnerControlTypeId;
487 case ROLE_SYSTEM_BUTTONMENU:
488 case ROLE_SYSTEM_MENUITEM: return UIA_MenuItemControlTypeId;
489 case ROLE_SYSTEM_PAGETABLIST: return UIA_TabControlTypeId;
490 case ROLE_SYSTEM_BUTTONDROPDOWN:
491 case ROLE_SYSTEM_SPLITBUTTON: return UIA_SplitButtonControlTypeId;
492 case ROLE_SYSTEM_SOUND:
493 case ROLE_SYSTEM_CURSOR:
494 case ROLE_SYSTEM_CARET:
495 case ROLE_SYSTEM_ALERT:
496 case ROLE_SYSTEM_CLIENT:
497 case ROLE_SYSTEM_CHART:
498 case ROLE_SYSTEM_DIALOG:
499 case ROLE_SYSTEM_BORDER:
500 case ROLE_SYSTEM_COLUMN:
501 case ROLE_SYSTEM_ROW:
502 case ROLE_SYSTEM_HELPBALLOON:
503 case ROLE_SYSTEM_CHARACTER:
504 case ROLE_SYSTEM_PROPERTYPAGE:
505 case ROLE_SYSTEM_DROPLIST:
506 case ROLE_SYSTEM_DIAL:
507 case ROLE_SYSTEM_HOTKEYFIELD:
508 case ROLE_SYSTEM_DIAGRAM:
509 case ROLE_SYSTEM_ANIMATION:
510 case ROLE_SYSTEM_EQUATION:
511 case ROLE_SYSTEM_WHITESPACE:
512 case ROLE_SYSTEM_IPADDRESS:
513 case ROLE_SYSTEM_OUTLINEBUTTON:
514 WARN("No UIA control type mapping for MSAA role %ld\n", role);
515 break;
517 default:
518 FIXME("UIA control type mapping unimplemented for MSAA role %ld\n", role);
519 break;
522 return 0;
526 * UiaProviderFromIAccessible IRawElementProviderSimple interface.
528 struct msaa_provider {
529 IRawElementProviderSimple IRawElementProviderSimple_iface;
530 IRawElementProviderFragment IRawElementProviderFragment_iface;
531 IRawElementProviderFragmentRoot IRawElementProviderFragmentRoot_iface;
532 ILegacyIAccessibleProvider ILegacyIAccessibleProvider_iface;
533 IProxyProviderWinEventHandler IProxyProviderWinEventHandler_iface;
534 LONG refcount;
536 IAccessible *acc;
537 IAccessible2 *ia2;
538 VARIANT cid;
539 HWND hwnd;
540 LONG control_type;
542 BOOL root_acc_check_ran;
543 BOOL is_root_acc;
545 IAccessible *parent;
546 INT child_pos;
549 static BOOL msaa_check_root_acc(struct msaa_provider *msaa_prov)
551 IAccessible *acc;
552 HRESULT hr;
554 if (msaa_prov->root_acc_check_ran)
555 return msaa_prov->is_root_acc;
557 msaa_prov->root_acc_check_ran = TRUE;
558 if (V_I4(&msaa_prov->cid) != CHILDID_SELF || msaa_prov->parent)
559 return FALSE;
561 hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
562 if (FAILED(hr))
563 return FALSE;
565 if (msaa_acc_compare(msaa_prov->acc, acc))
566 msaa_prov->is_root_acc = TRUE;
568 IAccessible_Release(acc);
569 return msaa_prov->is_root_acc;
572 static inline struct msaa_provider *impl_from_msaa_provider(IRawElementProviderSimple *iface)
574 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderSimple_iface);
577 HRESULT WINAPI msaa_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
579 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
581 *ppv = NULL;
582 if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
583 *ppv = iface;
584 else if (IsEqualIID(riid, &IID_IRawElementProviderFragment))
585 *ppv = &msaa_prov->IRawElementProviderFragment_iface;
586 else if (IsEqualIID(riid, &IID_IRawElementProviderFragmentRoot))
587 *ppv = &msaa_prov->IRawElementProviderFragmentRoot_iface;
588 else if (IsEqualIID(riid, &IID_ILegacyIAccessibleProvider))
589 *ppv = &msaa_prov->ILegacyIAccessibleProvider_iface;
590 else if (IsEqualIID(riid, &IID_IProxyProviderWinEventHandler))
591 *ppv = &msaa_prov->IProxyProviderWinEventHandler_iface;
592 else
593 return E_NOINTERFACE;
595 IRawElementProviderSimple_AddRef(iface);
596 return S_OK;
599 ULONG WINAPI msaa_provider_AddRef(IRawElementProviderSimple *iface)
601 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
602 ULONG refcount = InterlockedIncrement(&msaa_prov->refcount);
604 TRACE("%p, refcount %ld\n", iface, refcount);
606 return refcount;
609 ULONG WINAPI msaa_provider_Release(IRawElementProviderSimple *iface)
611 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
612 ULONG refcount = InterlockedDecrement(&msaa_prov->refcount);
614 TRACE("%p, refcount %ld\n", iface, refcount);
616 if (!refcount)
618 IAccessible_Release(msaa_prov->acc);
619 if (msaa_prov->parent)
620 IAccessible_Release(msaa_prov->parent);
621 if (msaa_prov->ia2)
622 IAccessible2_Release(msaa_prov->ia2);
623 free(msaa_prov);
626 return refcount;
629 HRESULT WINAPI msaa_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
630 enum ProviderOptions *ret_val)
632 TRACE("%p, %p\n", iface, ret_val);
633 *ret_val = ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading;
634 return S_OK;
637 HRESULT WINAPI msaa_provider_GetPatternProvider(IRawElementProviderSimple *iface,
638 PATTERNID pattern_id, IUnknown **ret_val)
640 TRACE("%p, %d, %p\n", iface, pattern_id, ret_val);
642 *ret_val = NULL;
643 switch (pattern_id)
645 case UIA_LegacyIAccessiblePatternId:
646 return IRawElementProviderSimple_QueryInterface(iface, &IID_IUnknown, (void **)ret_val);
648 default:
649 FIXME("Unimplemented patternId %d\n", pattern_id);
650 break;
653 return S_OK;
656 HRESULT WINAPI msaa_provider_GetPropertyValue(IRawElementProviderSimple *iface,
657 PROPERTYID prop_id, VARIANT *ret_val)
659 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
660 HRESULT hr;
661 VARIANT v;
663 TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
665 VariantInit(ret_val);
666 VariantInit(&v);
667 switch (prop_id)
669 case UIA_ProviderDescriptionPropertyId:
670 V_VT(ret_val) = VT_BSTR;
671 V_BSTR(ret_val) = SysAllocString(L"Wine: MSAA Proxy");
672 break;
674 case UIA_ControlTypePropertyId:
675 if (!msaa_prov->control_type)
677 hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
678 if (SUCCEEDED(hr) && (V_VT(&v) == VT_I4))
679 msaa_prov->control_type = msaa_role_to_uia_control_type(V_I4(&v));
682 if (msaa_prov->control_type)
683 variant_init_i4(ret_val, msaa_prov->control_type);
685 break;
687 case UIA_HasKeyboardFocusPropertyId:
688 hr = msaa_check_acc_state_hres(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_FOCUSED);
689 if (FAILED(hr))
690 return hr;
692 variant_init_bool(ret_val, hr == S_OK);
693 break;
695 case UIA_IsKeyboardFocusablePropertyId:
696 hr = msaa_check_acc_state_hres(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_FOCUSABLE);
697 if (FAILED(hr))
698 return hr;
700 variant_init_bool(ret_val, hr == S_OK);
701 break;
703 case UIA_IsEnabledPropertyId:
704 hr = msaa_check_acc_state_hres(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_UNAVAILABLE);
705 if (FAILED(hr))
706 return hr;
708 variant_init_bool(ret_val, hr == S_FALSE);
709 break;
711 case UIA_IsPasswordPropertyId:
712 hr = msaa_check_acc_state_hres(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_PROTECTED);
713 if (FAILED(hr))
714 return hr;
716 variant_init_bool(ret_val, hr == S_OK);
717 break;
719 case UIA_NamePropertyId:
721 BSTR name;
723 hr = IAccessible_get_accName(msaa_prov->acc, msaa_prov->cid, &name);
724 if (SUCCEEDED(hr) && name)
726 V_VT(ret_val) = VT_BSTR;
727 V_BSTR(ret_val) = name;
729 break;
732 case UIA_IsOffscreenPropertyId:
734 RECT rect[2] = { 0 };
735 RECT intersect_rect;
736 LONG width, height;
738 variant_init_bool(ret_val, FALSE);
739 if (msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_OFFSCREEN))
741 variant_init_bool(ret_val, TRUE);
742 break;
745 hr = IAccessible_accLocation(msaa_prov->acc, &rect[0].left, &rect[0].top, &width, &height, msaa_prov->cid);
746 if (FAILED(hr))
747 break;
749 rect[0].right = rect[0].left + width;
750 rect[0].bottom = rect[0].top + height;
751 SetLastError(NOERROR);
752 if (!GetClientRect(msaa_prov->hwnd, &rect[1]))
754 if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
755 variant_init_bool(ret_val, TRUE);
756 break;
759 SetLastError(NOERROR);
760 if (!MapWindowPoints(msaa_prov->hwnd, NULL, (POINT *)&rect[1], 2) && GetLastError())
762 if (GetLastError() == ERROR_INVALID_WINDOW_HANDLE)
763 variant_init_bool(ret_val, TRUE);
764 break;
767 variant_init_bool(ret_val, !IntersectRect(&intersect_rect, &rect[0], &rect[1]));
768 break;
771 default:
772 FIXME("Unimplemented propertyId %d\n", prop_id);
773 break;
776 return S_OK;
779 HRESULT WINAPI msaa_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
780 IRawElementProviderSimple **ret_val)
782 struct msaa_provider *msaa_prov = impl_from_msaa_provider(iface);
784 TRACE("%p, %p\n", iface, ret_val);
786 *ret_val = NULL;
787 if (msaa_check_root_acc(msaa_prov))
788 return UiaHostProviderFromHwnd(msaa_prov->hwnd, ret_val);
790 return S_OK;
793 static const IRawElementProviderSimpleVtbl msaa_provider_vtbl = {
794 msaa_provider_QueryInterface,
795 msaa_provider_AddRef,
796 msaa_provider_Release,
797 msaa_provider_get_ProviderOptions,
798 msaa_provider_GetPatternProvider,
799 msaa_provider_GetPropertyValue,
800 msaa_provider_get_HostRawElementProvider,
804 * IRawElementProviderFragment interface for UiaProviderFromIAccessible
805 * providers.
807 static inline struct msaa_provider *impl_from_msaa_fragment(IRawElementProviderFragment *iface)
809 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderFragment_iface);
812 static HRESULT WINAPI msaa_fragment_QueryInterface(IRawElementProviderFragment *iface, REFIID riid,
813 void **ppv)
815 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
816 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
819 static ULONG WINAPI msaa_fragment_AddRef(IRawElementProviderFragment *iface)
821 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
822 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
825 static ULONG WINAPI msaa_fragment_Release(IRawElementProviderFragment *iface)
827 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
828 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
831 static HRESULT WINAPI msaa_fragment_Navigate(IRawElementProviderFragment *iface,
832 enum NavigateDirection direction, IRawElementProviderFragment **ret_val)
834 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
835 LONG child_count, child_id, child_pos;
836 IRawElementProviderSimple *elprov;
837 IAccessible *acc;
838 HRESULT hr;
840 TRACE("%p, %d, %p\n", iface, direction, ret_val);
842 *ret_val = NULL;
843 switch (direction)
845 case NavigateDirection_Parent:
846 if (msaa_check_root_acc(msaa_prov))
847 break;
849 if (V_I4(&msaa_prov->cid) == CHILDID_SELF)
851 hr = msaa_acc_get_parent(msaa_prov->acc, &acc);
852 if (FAILED(hr) || !acc)
853 break;
855 else
856 acc = msaa_prov->acc;
858 hr = create_msaa_provider(acc, CHILDID_SELF, NULL, FALSE, FALSE, &elprov);
859 if (SUCCEEDED(hr))
861 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
862 *ret_val = &prov->IRawElementProviderFragment_iface;
865 if (acc != msaa_prov->acc)
866 IAccessible_Release(acc);
868 break;
870 case NavigateDirection_FirstChild:
871 case NavigateDirection_LastChild:
872 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
873 break;
875 hr = IAccessible_get_accChildCount(msaa_prov->acc, &child_count);
876 if (FAILED(hr) || !child_count)
877 break;
879 if (direction == NavigateDirection_FirstChild)
880 hr = msaa_acc_get_next_child(msaa_prov->acc, 1, DIR_FORWARD, &acc, &child_id,
881 &child_pos, TRUE);
882 else
883 hr = msaa_acc_get_next_child(msaa_prov->acc, child_count, DIR_REVERSE, &acc, &child_id,
884 &child_pos, TRUE);
886 if (FAILED(hr) || !acc)
887 break;
889 hr = create_msaa_provider(acc, child_id, NULL, FALSE, FALSE, &elprov);
890 if (SUCCEEDED(hr))
892 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
894 *ret_val = &prov->IRawElementProviderFragment_iface;
895 prov->parent = msaa_prov->acc;
896 IAccessible_AddRef(msaa_prov->acc);
897 if (acc != msaa_prov->acc)
898 prov->child_pos = child_pos;
899 else
900 prov->child_pos = child_id;
902 IAccessible_Release(acc);
904 break;
906 case NavigateDirection_NextSibling:
907 case NavigateDirection_PreviousSibling:
908 if (msaa_check_root_acc(msaa_prov))
909 break;
911 if (!msaa_prov->parent)
913 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
915 msaa_prov->parent = msaa_prov->acc;
916 IAccessible_AddRef(msaa_prov->acc);
917 msaa_prov->child_pos = V_I4(&msaa_prov->cid);
919 else
921 hr = msaa_acc_get_child_pos(msaa_prov->acc, &acc, &child_pos);
922 if (FAILED(hr) || !acc)
923 break;
924 msaa_prov->parent = acc;
925 msaa_prov->child_pos = child_pos;
929 if (direction == NavigateDirection_NextSibling)
930 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos + 1, DIR_FORWARD,
931 &acc, &child_id, &child_pos, TRUE);
932 else
933 hr = msaa_acc_get_next_child(msaa_prov->parent, msaa_prov->child_pos - 1, DIR_REVERSE,
934 &acc, &child_id, &child_pos, TRUE);
936 if (FAILED(hr) || !acc)
937 break;
939 hr = create_msaa_provider(acc, child_id, NULL, FALSE, FALSE, &elprov);
940 if (SUCCEEDED(hr))
942 struct msaa_provider *prov = impl_from_msaa_provider(elprov);
944 *ret_val = &prov->IRawElementProviderFragment_iface;
945 prov->parent = msaa_prov->parent;
946 IAccessible_AddRef(msaa_prov->parent);
947 if (acc != msaa_prov->acc)
948 prov->child_pos = child_pos;
949 else
950 prov->child_pos = child_id;
952 IAccessible_Release(acc);
954 break;
956 default:
957 FIXME("Invalid NavigateDirection %d\n", direction);
958 return E_INVALIDARG;
961 return S_OK;
964 static HRESULT WINAPI msaa_fragment_GetRuntimeId(IRawElementProviderFragment *iface,
965 SAFEARRAY **ret_val)
967 FIXME("%p, %p: stub!\n", iface, ret_val);
968 *ret_val = NULL;
969 return E_NOTIMPL;
972 static HRESULT WINAPI msaa_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface,
973 struct UiaRect *ret_val)
975 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
976 LONG left, top, width, height;
977 HRESULT hr;
979 TRACE("%p, %p\n", iface, ret_val);
981 memset(ret_val, 0, sizeof(*ret_val));
984 * If this IAccessible is at the root of its HWND, the BaseHwnd provider
985 * will supply the bounding rectangle.
987 if (msaa_check_root_acc(msaa_prov))
988 return S_OK;
990 if (msaa_check_acc_state(msaa_prov->acc, msaa_prov->cid, STATE_SYSTEM_OFFSCREEN))
991 return S_OK;
993 hr = IAccessible_accLocation(msaa_prov->acc, &left, &top, &width, &height, msaa_prov->cid);
994 if (FAILED(hr))
995 return hr;
997 ret_val->left = left;
998 ret_val->top = top;
999 ret_val->width = width;
1000 ret_val->height = height;
1002 return S_OK;
1005 static HRESULT WINAPI msaa_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface,
1006 SAFEARRAY **ret_val)
1008 FIXME("%p, %p: stub!\n", iface, ret_val);
1009 *ret_val = NULL;
1010 return E_NOTIMPL;
1013 static HRESULT WINAPI msaa_fragment_SetFocus(IRawElementProviderFragment *iface)
1015 FIXME("%p: stub!\n", iface);
1016 return E_NOTIMPL;
1019 static HRESULT WINAPI msaa_fragment_get_FragmentRoot(IRawElementProviderFragment *iface,
1020 IRawElementProviderFragmentRoot **ret_val)
1022 struct msaa_provider *msaa_prov = impl_from_msaa_fragment(iface);
1023 IRawElementProviderSimple *elprov;
1024 IAccessible *acc;
1025 HRESULT hr;
1027 TRACE("%p, %p\n", iface, ret_val);
1029 *ret_val = NULL;
1030 hr = AccessibleObjectFromWindow(msaa_prov->hwnd, OBJID_CLIENT, &IID_IAccessible, (void **)&acc);
1031 if (FAILED(hr) || !acc)
1032 return hr;
1034 hr = create_msaa_provider(acc, CHILDID_SELF, msaa_prov->hwnd, TRUE, TRUE, &elprov);
1035 IAccessible_Release(acc);
1036 if (FAILED(hr))
1037 return hr;
1039 hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragmentRoot, (void **)ret_val);
1040 IRawElementProviderSimple_Release(elprov);
1042 return hr;
1045 static const IRawElementProviderFragmentVtbl msaa_fragment_vtbl = {
1046 msaa_fragment_QueryInterface,
1047 msaa_fragment_AddRef,
1048 msaa_fragment_Release,
1049 msaa_fragment_Navigate,
1050 msaa_fragment_GetRuntimeId,
1051 msaa_fragment_get_BoundingRectangle,
1052 msaa_fragment_GetEmbeddedFragmentRoots,
1053 msaa_fragment_SetFocus,
1054 msaa_fragment_get_FragmentRoot,
1058 * IRawElementProviderFragmentRoot interface for UiaProviderFromIAccessible
1059 * providers.
1061 static inline struct msaa_provider *impl_from_msaa_fragment_root(IRawElementProviderFragmentRoot *iface)
1063 return CONTAINING_RECORD(iface, struct msaa_provider, IRawElementProviderFragmentRoot_iface);
1066 static HRESULT WINAPI msaa_fragment_root_QueryInterface(IRawElementProviderFragmentRoot *iface, REFIID riid,
1067 void **ppv)
1069 struct msaa_provider *msaa_prov = impl_from_msaa_fragment_root(iface);
1070 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
1073 static ULONG WINAPI msaa_fragment_root_AddRef(IRawElementProviderFragmentRoot *iface)
1075 struct msaa_provider *msaa_prov = impl_from_msaa_fragment_root(iface);
1076 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
1079 static ULONG WINAPI msaa_fragment_root_Release(IRawElementProviderFragmentRoot *iface)
1081 struct msaa_provider *msaa_prov = impl_from_msaa_fragment_root(iface);
1082 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
1085 static HRESULT WINAPI msaa_fragment_root_ElementProviderFromPoint(IRawElementProviderFragmentRoot *iface,
1086 double x, double y, IRawElementProviderFragment **ret_val)
1088 FIXME("%p, %f, %f, %p: stub!\n", iface, x, y, ret_val);
1089 *ret_val = NULL;
1090 return E_NOTIMPL;
1093 static HRESULT msaa_acc_get_focus(struct msaa_provider *prov, struct msaa_provider **out_prov)
1095 IRawElementProviderSimple *elprov;
1096 IAccessible *focus_acc = NULL;
1097 INT focus_cid = CHILDID_SELF;
1098 HWND hwnd = NULL;
1099 HRESULT hr;
1100 VARIANT v;
1102 *out_prov = NULL;
1104 if (V_I4(&prov->cid) != CHILDID_SELF)
1105 return S_OK;
1107 VariantInit(&v);
1108 hr = IAccessible_get_accFocus(prov->acc, &v);
1109 if (FAILED(hr) || (V_VT(&v) != VT_I4 && V_VT(&v) != VT_DISPATCH))
1111 VariantClear(&v);
1112 return hr;
1115 if (V_VT(&v) == VT_I4)
1117 IDispatch *disp = NULL;
1119 if (V_I4(&v) == CHILDID_SELF)
1120 return S_OK;
1122 hr = IAccessible_get_accChild(prov->acc, v, &disp);
1123 if (FAILED(hr))
1124 return hr;
1126 if (hr == S_FALSE)
1128 hwnd = prov->hwnd;
1129 focus_acc = prov->acc;
1130 IAccessible_AddRef(focus_acc);
1131 focus_cid = V_I4(&v);
1133 else if (disp)
1135 V_VT(&v) = VT_DISPATCH;
1136 V_DISPATCH(&v) = disp;
1138 else
1139 return E_FAIL;
1142 if (V_VT(&v) == VT_DISPATCH)
1144 hr = IDispatch_QueryInterface(V_DISPATCH(&v), &IID_IAccessible, (void **)&focus_acc);
1145 VariantClear(&v);
1146 if (FAILED(hr))
1147 return hr;
1149 hr = WindowFromAccessibleObject(focus_acc, &hwnd);
1150 if (FAILED(hr) || !hwnd)
1152 IAccessible_Release(focus_acc);
1153 return hr;
1157 hr = create_msaa_provider(focus_acc, focus_cid, hwnd, FALSE, FALSE, &elprov);
1158 IAccessible_Release(focus_acc);
1159 if (SUCCEEDED(hr))
1160 *out_prov = impl_from_msaa_provider(elprov);
1162 return hr;
1165 static HRESULT WINAPI msaa_fragment_root_GetFocus(IRawElementProviderFragmentRoot *iface,
1166 IRawElementProviderFragment **ret_val)
1168 struct msaa_provider *msaa_prov = impl_from_msaa_fragment_root(iface);
1169 struct msaa_provider *prov, *prov2;
1170 IRawElementProviderSimple *elprov;
1171 HRESULT hr;
1173 TRACE("%p, %p\n", iface, ret_val);
1175 *ret_val = NULL;
1176 if (V_I4(&msaa_prov->cid) != CHILDID_SELF)
1177 return S_OK;
1179 hr = create_msaa_provider(msaa_prov->acc, CHILDID_SELF, msaa_prov->hwnd, FALSE, FALSE, &elprov);
1180 if (FAILED(hr))
1181 return hr;
1183 prov = impl_from_msaa_provider(elprov);
1184 while (SUCCEEDED(msaa_acc_get_focus(prov, &prov2)))
1186 if (!prov2 || (msaa_check_acc_state_hres(prov2->acc, prov2->cid, STATE_SYSTEM_INVISIBLE) != S_FALSE) ||
1187 ((V_I4(&prov2->cid) == CHILDID_SELF) && msaa_acc_iface_cmp(prov->acc, prov2->acc)))
1189 if (prov2)
1190 IRawElementProviderSimple_Release(&prov2->IRawElementProviderSimple_iface);
1192 if (msaa_acc_iface_cmp(prov->acc, msaa_prov->acc) && V_I4(&prov->cid) == CHILDID_SELF)
1194 IRawElementProviderSimple_Release(&prov->IRawElementProviderSimple_iface);
1195 return S_OK;
1197 break;
1200 IRawElementProviderSimple_Release(&prov->IRawElementProviderSimple_iface);
1201 prov = prov2;
1204 hr = IRawElementProviderSimple_QueryInterface(&prov->IRawElementProviderSimple_iface, &IID_IRawElementProviderFragment, (void **)ret_val);
1205 IRawElementProviderSimple_Release(&prov->IRawElementProviderSimple_iface);
1206 return hr;
1209 static const IRawElementProviderFragmentRootVtbl msaa_fragment_root_vtbl = {
1210 msaa_fragment_root_QueryInterface,
1211 msaa_fragment_root_AddRef,
1212 msaa_fragment_root_Release,
1213 msaa_fragment_root_ElementProviderFromPoint,
1214 msaa_fragment_root_GetFocus,
1218 * ILegacyIAccessibleProvider interface for UiaProviderFromIAccessible
1219 * providers.
1221 static inline struct msaa_provider *impl_from_msaa_acc_provider(ILegacyIAccessibleProvider *iface)
1223 return CONTAINING_RECORD(iface, struct msaa_provider, ILegacyIAccessibleProvider_iface);
1226 static HRESULT WINAPI msaa_acc_provider_QueryInterface(ILegacyIAccessibleProvider *iface, REFIID riid, void **ppv)
1228 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1229 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
1232 static ULONG WINAPI msaa_acc_provider_AddRef(ILegacyIAccessibleProvider *iface)
1234 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1235 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
1238 static ULONG WINAPI msaa_acc_provider_Release(ILegacyIAccessibleProvider *iface)
1240 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1241 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
1244 static HRESULT WINAPI msaa_acc_provider_Select(ILegacyIAccessibleProvider *iface, LONG select_flags)
1246 FIXME("%p, %#lx: stub!\n", iface, select_flags);
1247 return E_NOTIMPL;
1250 static HRESULT WINAPI msaa_acc_provider_DoDefaultAction(ILegacyIAccessibleProvider *iface)
1252 FIXME("%p: stub!\n", iface);
1253 return E_NOTIMPL;
1256 static HRESULT WINAPI msaa_acc_provider_SetValue(ILegacyIAccessibleProvider *iface, LPCWSTR val)
1258 FIXME("%p, %p<%s>: stub!\n", iface, val, debugstr_w(val));
1259 return E_NOTIMPL;
1262 static HRESULT WINAPI msaa_acc_provider_GetIAccessible(ILegacyIAccessibleProvider *iface,
1263 IAccessible **out_acc)
1265 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1267 TRACE("%p, %p\n", iface, out_acc);
1269 *out_acc = NULL;
1270 if (msaa_acc_is_oleacc_proxy(msaa_prov->acc))
1271 return S_OK;
1273 return IAccessible_QueryInterface(msaa_prov->acc, &IID_IAccessible, (void **)out_acc);
1276 static HRESULT WINAPI msaa_acc_provider_get_ChildId(ILegacyIAccessibleProvider *iface, int *out_cid)
1278 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1280 TRACE("%p, %p\n", iface, out_cid);
1281 *out_cid = V_I4(&msaa_prov->cid);
1283 return S_OK;
1286 static HRESULT WINAPI msaa_acc_provider_get_Name(ILegacyIAccessibleProvider *iface, BSTR *out_name)
1288 FIXME("%p, %p: stub!\n", iface, out_name);
1289 return E_NOTIMPL;
1292 static HRESULT WINAPI msaa_acc_provider_get_Value(ILegacyIAccessibleProvider *iface, BSTR *out_value)
1294 FIXME("%p, %p: stub!\n", iface, out_value);
1295 return E_NOTIMPL;
1298 static HRESULT WINAPI msaa_acc_provider_get_Description(ILegacyIAccessibleProvider *iface,
1299 BSTR *out_description)
1301 FIXME("%p, %p: stub!\n", iface, out_description);
1302 return E_NOTIMPL;
1305 static HRESULT WINAPI msaa_acc_provider_get_Role(ILegacyIAccessibleProvider *iface, DWORD *out_role)
1307 struct msaa_provider *msaa_prov = impl_from_msaa_acc_provider(iface);
1308 HRESULT hr;
1309 VARIANT v;
1311 TRACE("%p, %p\n", iface, out_role);
1313 *out_role = 0;
1314 VariantInit(&v);
1315 hr = IAccessible_get_accRole(msaa_prov->acc, msaa_prov->cid, &v);
1316 if (SUCCEEDED(hr) && V_VT(&v) == VT_I4)
1317 *out_role = V_I4(&v);
1319 return S_OK;
1322 static HRESULT WINAPI msaa_acc_provider_get_State(ILegacyIAccessibleProvider *iface, DWORD *out_state)
1324 FIXME("%p, %p: stub!\n", iface, out_state);
1325 return E_NOTIMPL;
1328 static HRESULT WINAPI msaa_acc_provider_get_Help(ILegacyIAccessibleProvider *iface, BSTR *out_help)
1330 FIXME("%p, %p: stub!\n", iface, out_help);
1331 return E_NOTIMPL;
1334 static HRESULT WINAPI msaa_acc_provider_get_KeyboardShortcut(ILegacyIAccessibleProvider *iface,
1335 BSTR *out_kbd_shortcut)
1337 FIXME("%p, %p: stub!\n", iface, out_kbd_shortcut);
1338 return E_NOTIMPL;
1341 static HRESULT WINAPI msaa_acc_provider_GetSelection(ILegacyIAccessibleProvider *iface,
1342 SAFEARRAY **out_selected)
1344 FIXME("%p, %p: stub!\n", iface, out_selected);
1345 return E_NOTIMPL;
1348 static HRESULT WINAPI msaa_acc_provider_get_DefaultAction(ILegacyIAccessibleProvider *iface,
1349 BSTR *out_default_action)
1351 FIXME("%p, %p: stub!\n", iface, out_default_action);
1352 return E_NOTIMPL;
1355 static const ILegacyIAccessibleProviderVtbl msaa_acc_provider_vtbl = {
1356 msaa_acc_provider_QueryInterface,
1357 msaa_acc_provider_AddRef,
1358 msaa_acc_provider_Release,
1359 msaa_acc_provider_Select,
1360 msaa_acc_provider_DoDefaultAction,
1361 msaa_acc_provider_SetValue,
1362 msaa_acc_provider_GetIAccessible,
1363 msaa_acc_provider_get_ChildId,
1364 msaa_acc_provider_get_Name,
1365 msaa_acc_provider_get_Value,
1366 msaa_acc_provider_get_Description,
1367 msaa_acc_provider_get_Role,
1368 msaa_acc_provider_get_State,
1369 msaa_acc_provider_get_Help,
1370 msaa_acc_provider_get_KeyboardShortcut,
1371 msaa_acc_provider_GetSelection,
1372 msaa_acc_provider_get_DefaultAction,
1376 * IProxyProviderWinEventHandler interface for UiaProviderFromIAccessible
1377 * providers.
1379 static inline struct msaa_provider *impl_from_msaa_winevent_handler(IProxyProviderWinEventHandler *iface)
1381 return CONTAINING_RECORD(iface, struct msaa_provider, IProxyProviderWinEventHandler_iface);
1384 static HRESULT WINAPI msaa_winevent_handler_QueryInterface(IProxyProviderWinEventHandler *iface, REFIID riid,
1385 void **ppv)
1387 struct msaa_provider *msaa_prov = impl_from_msaa_winevent_handler(iface);
1388 return IRawElementProviderSimple_QueryInterface(&msaa_prov->IRawElementProviderSimple_iface, riid, ppv);
1391 static ULONG WINAPI msaa_winevent_handler_AddRef(IProxyProviderWinEventHandler *iface)
1393 struct msaa_provider *msaa_prov = impl_from_msaa_winevent_handler(iface);
1394 return IRawElementProviderSimple_AddRef(&msaa_prov->IRawElementProviderSimple_iface);
1397 static ULONG WINAPI msaa_winevent_handler_Release(IProxyProviderWinEventHandler *iface)
1399 struct msaa_provider *msaa_prov = impl_from_msaa_winevent_handler(iface);
1400 return IRawElementProviderSimple_Release(&msaa_prov->IRawElementProviderSimple_iface);
1403 static HRESULT WINAPI msaa_winevent_handler_RespondToWinEvent(IProxyProviderWinEventHandler *iface, DWORD event_id,
1404 HWND hwnd, LONG objid, LONG cid, IProxyProviderWinEventSink *event_sink)
1406 struct msaa_provider *msaa_prov = impl_from_msaa_winevent_handler(iface);
1407 HRESULT hr;
1409 TRACE("%p, %ld, %p, %ld, %ld, %p\n", iface, event_id, hwnd, objid, cid, event_sink);
1411 switch (event_id)
1413 case EVENT_SYSTEM_ALERT:
1414 hr = IProxyProviderWinEventSink_AddAutomationEvent(event_sink, &msaa_prov->IRawElementProviderSimple_iface,
1415 UIA_SystemAlertEventId);
1416 if (FAILED(hr))
1417 WARN("AddAutomationEvent failed with hr %#lx\n", hr);
1418 break;
1420 case EVENT_OBJECT_REORDER:
1421 case EVENT_OBJECT_SELECTION:
1422 case EVENT_OBJECT_NAMECHANGE:
1423 case EVENT_OBJECT_VALUECHANGE:
1424 case EVENT_OBJECT_HELPCHANGE:
1425 case EVENT_OBJECT_INVOKED:
1426 FIXME("WinEvent %ld currently unimplemented\n", event_id);
1427 return E_NOTIMPL;
1429 default:
1430 break;
1433 return S_OK;
1436 static const IProxyProviderWinEventHandlerVtbl msaa_winevent_handler_vtbl = {
1437 msaa_winevent_handler_QueryInterface,
1438 msaa_winevent_handler_AddRef,
1439 msaa_winevent_handler_Release,
1440 msaa_winevent_handler_RespondToWinEvent,
1443 HRESULT create_msaa_provider(IAccessible *acc, LONG child_id, HWND hwnd, BOOL root_acc_known,
1444 BOOL is_root_acc, IRawElementProviderSimple **elprov)
1446 struct msaa_provider *msaa_prov = calloc(1, sizeof(*msaa_prov));
1448 if (!msaa_prov)
1449 return E_OUTOFMEMORY;
1451 msaa_prov->IRawElementProviderSimple_iface.lpVtbl = &msaa_provider_vtbl;
1452 msaa_prov->IRawElementProviderFragment_iface.lpVtbl = &msaa_fragment_vtbl;
1453 msaa_prov->IRawElementProviderFragmentRoot_iface.lpVtbl = &msaa_fragment_root_vtbl;
1454 msaa_prov->ILegacyIAccessibleProvider_iface.lpVtbl = &msaa_acc_provider_vtbl;
1455 msaa_prov->IProxyProviderWinEventHandler_iface.lpVtbl = &msaa_winevent_handler_vtbl;
1456 msaa_prov->refcount = 1;
1457 variant_init_i4(&msaa_prov->cid, child_id);
1458 msaa_prov->acc = acc;
1459 IAccessible_AddRef(acc);
1460 msaa_prov->ia2 = msaa_acc_get_ia2(acc);
1462 if (!hwnd)
1464 HRESULT hr;
1466 hr = WindowFromAccessibleObject(acc, &msaa_prov->hwnd);
1467 if (FAILED(hr))
1468 WARN("WindowFromAccessibleObject failed with hr %#lx\n", hr);
1470 else
1471 msaa_prov->hwnd = hwnd;
1473 if (root_acc_known)
1475 msaa_prov->root_acc_check_ran = TRUE;
1476 msaa_prov->is_root_acc = is_root_acc;
1479 *elprov = &msaa_prov->IRawElementProviderSimple_iface;
1481 return S_OK;
1484 /***********************************************************************
1485 * UiaProviderFromIAccessible (uiautomationcore.@)
1487 HRESULT WINAPI UiaProviderFromIAccessible(IAccessible *acc, LONG child_id, DWORD flags,
1488 IRawElementProviderSimple **elprov)
1490 HWND hwnd = NULL;
1491 HRESULT hr;
1493 TRACE("(%p, %ld, %#lx, %p)\n", acc, child_id, flags, elprov);
1495 if (elprov)
1496 *elprov = NULL;
1498 if (!elprov)
1499 return E_POINTER;
1500 if (!acc)
1501 return E_INVALIDARG;
1503 if (flags != UIA_PFIA_DEFAULT)
1505 FIXME("unsupported flags %#lx\n", flags);
1506 return E_NOTIMPL;
1509 if (msaa_acc_is_oleacc_proxy(acc))
1511 WARN("Cannot wrap an oleacc proxy IAccessible!\n");
1512 return E_INVALIDARG;
1515 hr = WindowFromAccessibleObject(acc, &hwnd);
1516 if (FAILED(hr))
1517 return hr;
1518 if (!hwnd)
1519 return E_FAIL;
1521 return create_msaa_provider(acc, child_id, hwnd, FALSE, FALSE, elprov);
1524 static HRESULT uia_get_hr_for_last_error(void)
1526 DWORD last_err = GetLastError();
1528 switch (last_err)
1530 case ERROR_INVALID_WINDOW_HANDLE:
1531 return UIA_E_ELEMENTNOTAVAILABLE;
1533 case ERROR_TIMEOUT:
1534 return UIA_E_TIMEOUT;
1536 default:
1537 return E_FAIL;
1541 #define UIA_DEFAULT_MSG_TIMEOUT 10000
1542 static HRESULT uia_send_message_timeout(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, UINT timeout, LRESULT *lres)
1544 *lres = 0;
1545 if (!SendMessageTimeoutW(hwnd, msg, wparam, lparam, SMTO_NORMAL, timeout, (PDWORD_PTR)lres))
1546 return uia_get_hr_for_last_error();
1548 return S_OK;
1551 static HRESULT get_uia_control_type_for_hwnd(HWND hwnd, int *control_type)
1553 LONG_PTR style, ex_style;
1555 *control_type = 0;
1556 if ((ex_style = GetWindowLongPtrW(hwnd, GWL_EXSTYLE)) & WS_EX_APPWINDOW)
1558 *control_type = UIA_WindowControlTypeId;
1559 return S_OK;
1562 SetLastError(NO_ERROR);
1563 if (!(style = GetWindowLongPtrW(hwnd, GWL_STYLE)) && (GetLastError() != NO_ERROR))
1564 return uia_get_hr_for_last_error();
1567 * Non-caption HWNDs that are popups or tool windows aren't considered full
1568 * windows, only panes.
1570 if (((style & WS_CAPTION) != WS_CAPTION) && ((ex_style & WS_EX_TOOLWINDOW) || (style & WS_POPUP)))
1572 *control_type = UIA_PaneControlTypeId;
1573 return S_OK;
1576 /* Non top-level HWNDs are considered panes as well. */
1577 if (!uia_is_top_level_hwnd(hwnd))
1578 *control_type = UIA_PaneControlTypeId;
1579 else
1580 *control_type = UIA_WindowControlTypeId;
1582 return S_OK;
1586 * Default ProviderType_BaseHwnd IRawElementProviderSimple interface.
1588 struct base_hwnd_provider {
1589 IRawElementProviderSimple IRawElementProviderSimple_iface;
1590 IRawElementProviderFragment IRawElementProviderFragment_iface;
1591 LONG refcount;
1593 HWND hwnd;
1596 static inline struct base_hwnd_provider *impl_from_base_hwnd_provider(IRawElementProviderSimple *iface)
1598 return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderSimple_iface);
1601 static HRESULT WINAPI base_hwnd_provider_QueryInterface(IRawElementProviderSimple *iface, REFIID riid, void **ppv)
1603 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface);
1605 *ppv = NULL;
1606 if (IsEqualIID(riid, &IID_IRawElementProviderSimple) || IsEqualIID(riid, &IID_IUnknown))
1607 *ppv = iface;
1608 else if (IsEqualIID(riid, &IID_IRawElementProviderFragment))
1609 *ppv = &base_hwnd_prov->IRawElementProviderFragment_iface;
1610 else
1611 return E_NOINTERFACE;
1613 IRawElementProviderSimple_AddRef(iface);
1614 return S_OK;
1617 static ULONG WINAPI base_hwnd_provider_AddRef(IRawElementProviderSimple *iface)
1619 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface);
1620 ULONG refcount = InterlockedIncrement(&base_hwnd_prov->refcount);
1622 TRACE("%p, refcount %ld\n", iface, refcount);
1624 return refcount;
1627 static ULONG WINAPI base_hwnd_provider_Release(IRawElementProviderSimple *iface)
1629 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface);
1630 ULONG refcount = InterlockedDecrement(&base_hwnd_prov->refcount);
1632 TRACE("%p, refcount %ld\n", iface, refcount);
1634 if (!refcount)
1635 free(base_hwnd_prov);
1637 return refcount;
1640 static HRESULT WINAPI base_hwnd_provider_get_ProviderOptions(IRawElementProviderSimple *iface,
1641 enum ProviderOptions *ret_val)
1643 TRACE("%p, %p\n", iface, ret_val);
1644 *ret_val = ProviderOptions_ClientSideProvider;
1645 return S_OK;
1648 static HRESULT WINAPI base_hwnd_provider_GetPatternProvider(IRawElementProviderSimple *iface,
1649 PATTERNID pattern_id, IUnknown **ret_val)
1651 FIXME("%p, %d, %p: stub\n", iface, pattern_id, ret_val);
1652 *ret_val = NULL;
1653 return E_NOTIMPL;
1656 static HRESULT WINAPI base_hwnd_provider_GetPropertyValue(IRawElementProviderSimple *iface,
1657 PROPERTYID prop_id, VARIANT *ret_val)
1659 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_provider(iface);
1660 HRESULT hr = S_OK;
1662 TRACE("%p, %d, %p\n", iface, prop_id, ret_val);
1664 VariantInit(ret_val);
1665 if (!IsWindow(base_hwnd_prov->hwnd))
1666 return UIA_E_ELEMENTNOTAVAILABLE;
1668 switch (prop_id)
1670 case UIA_ProviderDescriptionPropertyId:
1671 V_VT(ret_val) = VT_BSTR;
1672 V_BSTR(ret_val) = SysAllocString(L"Wine: HWND Proxy");
1673 break;
1675 case UIA_NativeWindowHandlePropertyId:
1676 V_VT(ret_val) = VT_I4;
1677 V_I4(ret_val) = HandleToUlong(base_hwnd_prov->hwnd);
1678 break;
1680 case UIA_ProcessIdPropertyId:
1682 DWORD pid;
1684 if (!GetWindowThreadProcessId(base_hwnd_prov->hwnd, &pid))
1685 return UIA_E_ELEMENTNOTAVAILABLE;
1687 V_VT(ret_val) = VT_I4;
1688 V_I4(ret_val) = pid;
1689 break;
1692 case UIA_ClassNamePropertyId:
1694 WCHAR buf[256] = { 0 };
1696 if (!GetClassNameW(base_hwnd_prov->hwnd, buf, ARRAY_SIZE(buf)))
1697 hr = uia_get_hr_for_last_error();
1698 else
1700 V_VT(ret_val) = VT_BSTR;
1701 V_BSTR(ret_val) = SysAllocString(buf);
1703 break;
1706 case UIA_NamePropertyId:
1708 LRESULT lres;
1710 V_VT(ret_val) = VT_BSTR;
1711 V_BSTR(ret_val) = SysAllocString(L"");
1712 hr = uia_send_message_timeout(base_hwnd_prov->hwnd, WM_GETTEXTLENGTH, 0, 0, UIA_DEFAULT_MSG_TIMEOUT, &lres);
1713 if (FAILED(hr) || !lres)
1714 break;
1716 if (!SysReAllocStringLen(&V_BSTR(ret_val), NULL, lres))
1718 hr = E_OUTOFMEMORY;
1719 break;
1722 hr = uia_send_message_timeout(base_hwnd_prov->hwnd, WM_GETTEXT, SysStringLen(V_BSTR(ret_val)) + 1,
1723 (LPARAM)V_BSTR(ret_val), UIA_DEFAULT_MSG_TIMEOUT, &lres);
1724 break;
1727 case UIA_ControlTypePropertyId:
1729 int control_type;
1731 hr = get_uia_control_type_for_hwnd(base_hwnd_prov->hwnd, &control_type);
1732 if (SUCCEEDED(hr))
1734 V_VT(ret_val) = VT_I4;
1735 V_I4(ret_val) = control_type;
1737 break;
1740 default:
1741 break;
1744 if (FAILED(hr))
1745 VariantClear(ret_val);
1747 return hr;
1750 static HRESULT WINAPI base_hwnd_provider_get_HostRawElementProvider(IRawElementProviderSimple *iface,
1751 IRawElementProviderSimple **ret_val)
1753 TRACE("%p, %p\n", iface, ret_val);
1754 *ret_val = NULL;
1755 return S_OK;
1758 static const IRawElementProviderSimpleVtbl base_hwnd_provider_vtbl = {
1759 base_hwnd_provider_QueryInterface,
1760 base_hwnd_provider_AddRef,
1761 base_hwnd_provider_Release,
1762 base_hwnd_provider_get_ProviderOptions,
1763 base_hwnd_provider_GetPatternProvider,
1764 base_hwnd_provider_GetPropertyValue,
1765 base_hwnd_provider_get_HostRawElementProvider,
1769 * IRawElementProviderFragment interface for default ProviderType_BaseHwnd
1770 * providers.
1772 static inline struct base_hwnd_provider *impl_from_base_hwnd_fragment(IRawElementProviderFragment *iface)
1774 return CONTAINING_RECORD(iface, struct base_hwnd_provider, IRawElementProviderFragment_iface);
1777 static HRESULT WINAPI base_hwnd_fragment_QueryInterface(IRawElementProviderFragment *iface, REFIID riid,
1778 void **ppv)
1780 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface);
1781 return IRawElementProviderSimple_QueryInterface(&base_hwnd_prov->IRawElementProviderSimple_iface, riid, ppv);
1784 static ULONG WINAPI base_hwnd_fragment_AddRef(IRawElementProviderFragment *iface)
1786 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface);
1787 return IRawElementProviderSimple_AddRef(&base_hwnd_prov->IRawElementProviderSimple_iface);
1790 static ULONG WINAPI base_hwnd_fragment_Release(IRawElementProviderFragment *iface)
1792 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface);
1793 return IRawElementProviderSimple_Release(&base_hwnd_prov->IRawElementProviderSimple_iface);
1796 static HRESULT WINAPI base_hwnd_fragment_Navigate(IRawElementProviderFragment *iface,
1797 enum NavigateDirection direction, IRawElementProviderFragment **ret_val)
1799 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface);
1800 IRawElementProviderSimple *elprov = NULL;
1801 HRESULT hr = S_OK;
1803 TRACE("%p, %d, %p\n", iface, direction, ret_val);
1805 *ret_val = NULL;
1807 switch (direction)
1809 case NavigateDirection_Parent:
1811 HWND parent, owner;
1814 * Top level owned windows have their owner window as a parent instead
1815 * of the desktop window.
1817 if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && (owner = GetWindow(base_hwnd_prov->hwnd, GW_OWNER)))
1818 parent = owner;
1819 else
1820 parent = GetAncestor(base_hwnd_prov->hwnd, GA_PARENT);
1822 if (parent)
1823 hr = create_base_hwnd_provider(parent, &elprov);
1824 break;
1827 case NavigateDirection_FirstChild:
1828 case NavigateDirection_LastChild:
1829 case NavigateDirection_PreviousSibling:
1830 case NavigateDirection_NextSibling:
1831 FIXME("Unimplemented NavigateDirection %d\n", direction);
1832 return E_NOTIMPL;
1834 default:
1835 FIXME("Invalid NavigateDirection %d\n", direction);
1836 return E_INVALIDARG;
1839 if (elprov)
1841 hr = IRawElementProviderSimple_QueryInterface(elprov, &IID_IRawElementProviderFragment, (void **)ret_val);
1842 IRawElementProviderSimple_Release(elprov);
1845 return hr;
1848 static HRESULT WINAPI base_hwnd_fragment_GetRuntimeId(IRawElementProviderFragment *iface,
1849 SAFEARRAY **ret_val)
1851 FIXME("%p, %p: stub!\n", iface, ret_val);
1852 *ret_val = NULL;
1853 return E_NOTIMPL;
1856 static HRESULT WINAPI base_hwnd_fragment_get_BoundingRectangle(IRawElementProviderFragment *iface,
1857 struct UiaRect *ret_val)
1859 struct base_hwnd_provider *base_hwnd_prov = impl_from_base_hwnd_fragment(iface);
1860 RECT rect = { 0 };
1862 TRACE("%p, %p\n", iface, ret_val);
1864 memset(ret_val, 0, sizeof(*ret_val));
1866 /* Top level minimized window - Return empty rect. */
1867 if (uia_is_top_level_hwnd(base_hwnd_prov->hwnd) && IsIconic(base_hwnd_prov->hwnd))
1868 return S_OK;
1870 if (!GetWindowRect(base_hwnd_prov->hwnd, &rect))
1871 return uia_get_hr_for_last_error();
1873 ret_val->left = rect.left;
1874 ret_val->top = rect.top;
1875 ret_val->width = (rect.right - rect.left);
1876 ret_val->height = (rect.bottom - rect.top);
1878 return S_OK;
1881 static HRESULT WINAPI base_hwnd_fragment_GetEmbeddedFragmentRoots(IRawElementProviderFragment *iface,
1882 SAFEARRAY **ret_val)
1884 FIXME("%p, %p: stub!\n", iface, ret_val);
1885 *ret_val = NULL;
1886 return E_NOTIMPL;
1889 static HRESULT WINAPI base_hwnd_fragment_SetFocus(IRawElementProviderFragment *iface)
1891 FIXME("%p: stub!\n", iface);
1892 return E_NOTIMPL;
1895 static HRESULT WINAPI base_hwnd_fragment_get_FragmentRoot(IRawElementProviderFragment *iface,
1896 IRawElementProviderFragmentRoot **ret_val)
1898 FIXME("%p, %p: stub!\n", iface, ret_val);
1899 *ret_val = NULL;
1900 return E_NOTIMPL;
1903 static const IRawElementProviderFragmentVtbl base_hwnd_fragment_vtbl = {
1904 base_hwnd_fragment_QueryInterface,
1905 base_hwnd_fragment_AddRef,
1906 base_hwnd_fragment_Release,
1907 base_hwnd_fragment_Navigate,
1908 base_hwnd_fragment_GetRuntimeId,
1909 base_hwnd_fragment_get_BoundingRectangle,
1910 base_hwnd_fragment_GetEmbeddedFragmentRoots,
1911 base_hwnd_fragment_SetFocus,
1912 base_hwnd_fragment_get_FragmentRoot,
1915 HRESULT create_base_hwnd_provider(HWND hwnd, IRawElementProviderSimple **elprov)
1917 struct base_hwnd_provider *base_hwnd_prov;
1919 *elprov = NULL;
1921 if (!hwnd)
1922 return E_INVALIDARG;
1924 if (!IsWindow(hwnd))
1925 return UIA_E_ELEMENTNOTAVAILABLE;
1927 if (!(base_hwnd_prov = calloc(1, sizeof(*base_hwnd_prov))))
1928 return E_OUTOFMEMORY;
1930 base_hwnd_prov->IRawElementProviderSimple_iface.lpVtbl = &base_hwnd_provider_vtbl;
1931 base_hwnd_prov->IRawElementProviderFragment_iface.lpVtbl = &base_hwnd_fragment_vtbl;
1932 base_hwnd_prov->refcount = 1;
1933 base_hwnd_prov->hwnd = hwnd;
1934 *elprov = &base_hwnd_prov->IRawElementProviderSimple_iface;
1936 return S_OK;
1940 * UI Automation provider thread functions.
1942 struct uia_provider_thread
1944 struct rb_tree node_map;
1945 struct list nodes_list;
1946 HANDLE hthread;
1947 HWND hwnd;
1948 LONG ref;
1951 static struct uia_provider_thread provider_thread;
1952 static CRITICAL_SECTION provider_thread_cs;
1953 static CRITICAL_SECTION_DEBUG provider_thread_cs_debug =
1955 0, 0, &provider_thread_cs,
1956 { &provider_thread_cs_debug.ProcessLocksList, &provider_thread_cs_debug.ProcessLocksList },
1957 0, 0, { (DWORD_PTR)(__FILE__ ": provider_thread_cs") }
1959 static CRITICAL_SECTION provider_thread_cs = { &provider_thread_cs_debug, -1, 0, 0, 0, 0 };
1961 struct uia_provider_thread_map_entry
1963 struct rb_entry entry;
1965 SAFEARRAY *runtime_id;
1966 struct list nodes_list;
1969 static int uia_runtime_id_compare(const void *key, const struct rb_entry *entry)
1971 struct uia_provider_thread_map_entry *prov_entry = RB_ENTRY_VALUE(entry, struct uia_provider_thread_map_entry, entry);
1972 return uia_compare_safearrays(prov_entry->runtime_id, (SAFEARRAY *)key, UIAutomationType_IntArray);
1975 void uia_provider_thread_remove_node(HUIANODE node)
1977 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
1979 TRACE("Removing node %p\n", node);
1981 EnterCriticalSection(&provider_thread_cs);
1983 list_remove(&node_data->prov_thread_list_entry);
1984 list_init(&node_data->prov_thread_list_entry);
1985 if (!list_empty(&node_data->node_map_list_entry))
1987 list_remove(&node_data->node_map_list_entry);
1988 list_init(&node_data->node_map_list_entry);
1989 if (list_empty(&node_data->map->nodes_list))
1991 rb_remove(&provider_thread.node_map, &node_data->map->entry);
1992 SafeArrayDestroy(node_data->map->runtime_id);
1993 free(node_data->map);
1995 node_data->map = NULL;
1998 LeaveCriticalSection(&provider_thread_cs);
2001 static void uia_provider_thread_disconnect_node(SAFEARRAY *sa)
2003 struct rb_entry *rb_entry;
2005 EnterCriticalSection(&provider_thread_cs);
2007 /* Provider thread hasn't been started, no nodes to disconnect. */
2008 if (!provider_thread.ref)
2009 goto exit;
2011 rb_entry = rb_get(&provider_thread.node_map, sa);
2012 if (rb_entry)
2014 struct uia_provider_thread_map_entry *prov_map;
2015 struct list *cursor, *cursor2;
2016 struct uia_node *node_data;
2018 prov_map = RB_ENTRY_VALUE(rb_entry, struct uia_provider_thread_map_entry, entry);
2019 LIST_FOR_EACH_SAFE(cursor, cursor2, &prov_map->nodes_list)
2021 node_data = LIST_ENTRY(cursor, struct uia_node, node_map_list_entry);
2023 list_remove(cursor);
2024 list_remove(&node_data->prov_thread_list_entry);
2025 list_init(&node_data->prov_thread_list_entry);
2026 list_init(&node_data->node_map_list_entry);
2027 node_data->map = NULL;
2029 IWineUiaNode_disconnect(&node_data->IWineUiaNode_iface);
2032 rb_remove(&provider_thread.node_map, &prov_map->entry);
2033 SafeArrayDestroy(prov_map->runtime_id);
2034 free(prov_map);
2037 exit:
2038 LeaveCriticalSection(&provider_thread_cs);
2041 static HRESULT uia_provider_thread_add_node(HUIANODE node, SAFEARRAY *rt_id)
2043 struct uia_node *node_data = impl_from_IWineUiaNode((IWineUiaNode *)node);
2044 int prov_type = get_node_provider_type_at_idx(node_data, 0);
2045 struct uia_provider *prov_data;
2046 HRESULT hr = S_OK;
2048 prov_data = impl_from_IWineUiaProvider(node_data->prov[prov_type]);
2049 node_data->nested_node = prov_data->return_nested_node = prov_data->refuse_hwnd_node_providers = TRUE;
2051 TRACE("Adding node %p\n", node);
2053 EnterCriticalSection(&provider_thread_cs);
2054 list_add_tail(&provider_thread.nodes_list, &node_data->prov_thread_list_entry);
2056 /* If we have a runtime ID, create an entry in the rb tree. */
2057 if (rt_id)
2059 struct uia_provider_thread_map_entry *prov_map;
2060 struct rb_entry *rb_entry;
2062 if ((rb_entry = rb_get(&provider_thread.node_map, rt_id)))
2063 prov_map = RB_ENTRY_VALUE(rb_entry, struct uia_provider_thread_map_entry, entry);
2064 else
2066 prov_map = calloc(1, sizeof(*prov_map));
2067 if (!prov_map)
2069 hr = E_OUTOFMEMORY;
2070 goto exit;
2073 hr = SafeArrayCopy(rt_id, &prov_map->runtime_id);
2074 if (FAILED(hr))
2076 free(prov_map);
2077 goto exit;
2079 list_init(&prov_map->nodes_list);
2080 rb_put(&provider_thread.node_map, prov_map->runtime_id, &prov_map->entry);
2083 list_add_tail(&prov_map->nodes_list, &node_data->node_map_list_entry);
2084 node_data->map = prov_map;
2087 exit:
2088 LeaveCriticalSection(&provider_thread_cs);
2090 return hr;
2093 #define WM_GET_OBJECT_UIA_NODE (WM_USER + 1)
2094 #define WM_UIA_PROVIDER_THREAD_STOP (WM_USER + 2)
2095 static LRESULT CALLBACK uia_provider_thread_msg_proc(HWND hwnd, UINT msg, WPARAM wparam,
2096 LPARAM lparam)
2098 switch (msg)
2100 case WM_GET_OBJECT_UIA_NODE:
2102 SAFEARRAY *rt_id = (SAFEARRAY *)wparam;
2103 HUIANODE node = (HUIANODE)lparam;
2104 LRESULT lr;
2106 if (FAILED(uia_provider_thread_add_node(node, rt_id)))
2108 WARN("Failed to add node %p to provider thread list.\n", node);
2109 return 0;
2113 * LresultFromObject returns an index into the global atom string table,
2114 * which has a valid range of 0xc000-0xffff.
2116 lr = LresultFromObject(&IID_IWineUiaNode, 0, (IUnknown *)node);
2117 if ((lr > 0xffff) || (lr < 0xc000))
2119 WARN("Got invalid lresult %Ix\n", lr);
2120 lr = 0;
2123 return lr;
2126 default:
2127 break;
2130 return DefWindowProcW(hwnd, msg, wparam, lparam);
2133 static DWORD WINAPI uia_provider_thread_proc(void *arg)
2135 HANDLE initialized_event = arg;
2136 HWND hwnd;
2137 MSG msg;
2139 CoInitializeEx(NULL, COINIT_MULTITHREADED);
2140 hwnd = CreateWindowW(L"Message", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
2141 if (!hwnd)
2143 WARN("CreateWindow failed: %ld\n", GetLastError());
2144 CoUninitialize();
2145 FreeLibraryAndExitThread(huia_module, 1);
2148 SetWindowLongPtrW(hwnd, GWLP_WNDPROC, (LONG_PTR)uia_provider_thread_msg_proc);
2149 provider_thread.hwnd = hwnd;
2151 /* Initialization complete, thread can now process window messages. */
2152 SetEvent(initialized_event);
2153 TRACE("Provider thread started.\n");
2154 while (GetMessageW(&msg, NULL, 0, 0))
2156 if (msg.message == WM_UIA_PROVIDER_THREAD_STOP)
2157 break;
2158 TranslateMessage(&msg);
2159 DispatchMessageW(&msg);
2162 TRACE("Shutting down UI Automation provider thread.\n");
2164 DestroyWindow(hwnd);
2165 CoUninitialize();
2166 FreeLibraryAndExitThread(huia_module, 0);
2169 static BOOL uia_start_provider_thread(void)
2171 BOOL started = TRUE;
2173 EnterCriticalSection(&provider_thread_cs);
2174 if (++provider_thread.ref == 1)
2176 HANDLE ready_event;
2177 HANDLE events[2];
2178 HMODULE hmodule;
2179 DWORD wait_obj;
2181 /* Increment DLL reference count. */
2182 GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
2183 (const WCHAR *)uia_start_provider_thread, &hmodule);
2185 list_init(&provider_thread.nodes_list);
2186 rb_init(&provider_thread.node_map, uia_runtime_id_compare);
2187 events[0] = ready_event = CreateEventW(NULL, FALSE, FALSE, NULL);
2188 if (!(provider_thread.hthread = CreateThread(NULL, 0, uia_provider_thread_proc,
2189 ready_event, 0, NULL)))
2191 FreeLibrary(hmodule);
2192 started = FALSE;
2193 goto exit;
2196 events[1] = provider_thread.hthread;
2197 wait_obj = WaitForMultipleObjects(2, events, FALSE, INFINITE);
2198 if (wait_obj != WAIT_OBJECT_0)
2200 CloseHandle(provider_thread.hthread);
2201 started = FALSE;
2204 exit:
2205 CloseHandle(ready_event);
2206 if (!started)
2208 WARN("Failed to start provider thread\n");
2209 memset(&provider_thread, 0, sizeof(provider_thread));
2213 LeaveCriticalSection(&provider_thread_cs);
2214 return started;
2217 void uia_stop_provider_thread(void)
2219 EnterCriticalSection(&provider_thread_cs);
2220 if (!--provider_thread.ref)
2222 PostMessageW(provider_thread.hwnd, WM_UIA_PROVIDER_THREAD_STOP, 0, 0);
2223 CloseHandle(provider_thread.hthread);
2224 if (!list_empty(&provider_thread.nodes_list))
2225 ERR("Provider thread shutdown with nodes still in the list\n");
2226 memset(&provider_thread, 0, sizeof(provider_thread));
2228 LeaveCriticalSection(&provider_thread_cs);
2232 * Pass our IWineUiaNode interface to the provider thread for marshaling. UI
2233 * Automation has to work regardless of whether or not COM is initialized on
2234 * the thread calling UiaReturnRawElementProvider.
2236 LRESULT uia_lresult_from_node(HUIANODE huianode)
2238 SAFEARRAY *rt_id;
2239 LRESULT lr = 0;
2240 HRESULT hr;
2242 hr = UiaGetRuntimeId(huianode, &rt_id);
2243 if (SUCCEEDED(hr) && uia_start_provider_thread())
2244 lr = SendMessageW(provider_thread.hwnd, WM_GET_OBJECT_UIA_NODE, (WPARAM)rt_id, (LPARAM)huianode);
2246 if (FAILED(hr))
2247 WARN("UiaGetRuntimeId failed with hr %#lx\n", hr);
2250 * LresultFromObject increases refcnt by 1. If LresultFromObject
2251 * failed or wasn't called, this is expected to release the node.
2253 UiaNodeRelease(huianode);
2254 SafeArrayDestroy(rt_id);
2255 return lr;
2258 /***********************************************************************
2259 * UiaReturnRawElementProvider (uiautomationcore.@)
2261 LRESULT WINAPI UiaReturnRawElementProvider(HWND hwnd, WPARAM wparam,
2262 LPARAM lparam, IRawElementProviderSimple *elprov)
2264 HUIANODE node;
2265 HRESULT hr;
2267 TRACE("(%p, %Ix, %#Ix, %p)\n", hwnd, wparam, lparam, elprov);
2269 if (!wparam && !lparam && !elprov)
2271 FIXME("UIA-to-MSAA bridge not implemented, no provider map to free.\n");
2272 return 0;
2275 if (lparam != UiaRootObjectId)
2277 FIXME("Unsupported object id %Id, ignoring.\n", lparam);
2278 return 0;
2281 hr = create_uia_node_from_elprov(elprov, &node, FALSE, 0);
2282 if (FAILED(hr))
2284 WARN("Failed to create HUIANODE with hr %#lx\n", hr);
2285 return 0;
2288 return uia_lresult_from_node(node);
2291 /***********************************************************************
2292 * UiaDisconnectProvider (uiautomationcore.@)
2294 HRESULT WINAPI UiaDisconnectProvider(IRawElementProviderSimple *elprov)
2296 SAFEARRAY *sa;
2297 HUIANODE node;
2298 HRESULT hr;
2300 TRACE("(%p)\n", elprov);
2302 hr = create_uia_node_from_elprov(elprov, &node, FALSE, 0);
2303 if (FAILED(hr))
2304 return hr;
2306 hr = UiaGetRuntimeId(node, &sa);
2307 UiaNodeRelease(node);
2308 if (FAILED(hr))
2309 return hr;
2311 if (!sa)
2312 return E_INVALIDARG;
2314 uia_provider_thread_disconnect_node(sa);
2316 SafeArrayDestroy(sa);
2318 return S_OK;