Hello @Perry Jones ,
Thanks for the clear write-up. I reproduced this on a Windows 11 desktop (build 26200) and enumerated the taskbar via UI Automation. A few points that may help:
1. It's still under Shell_TrayWnd (explorer.exe), but it is not a direct child. It sits two levels deep: Shell_TrayWnd > Windows.UI.Input.InputSite.WindowClass >Taskbar.TaskbarFrameAutomationPeer > the Start element (AutomationId="StartButton", Name="Start", ControlType.Button, ClassName="ToggleButton"). So, a TreeScope.Children or shallow search will miss it, you likely need TreeScope.Descendants.
2. On a multi-monitor setup I saw two matches for AutomationId="StartButton" , one under Shell_TrayWnd (primary) and one under Shell_SecondaryTrayWnd (secondary). If you search from the desktop root with FindFirst, you may get the button on the wrong monitor, so the overlay ends up off the observed screen. Anchoring to a specific taskbar window instead of the root should avoid this.
Answers to your specific questions
-
Shell_TrayWnd+ explorer.exe: still the correct anchor on current builds. -
AutomationId="StartButton": reliable on this build, but nested inside the XAML island, so search descendants. - Search from root: not recommended with multiple monitors (duplicate matches) — anchor to the tray window.
- Raw vs Control View: Control View was sufficient here.
- Fallback: if the AutomationId changes,
Name="Start"+ControlType.ButtonwithinTaskbar.TaskbarFrameAutomationPeerworks as a secondary match.
Minimal resolver
static AutomationElement ResolveStartButton()
{
var tray = AutomationElement.RootElement.FindFirst(
TreeScope.Children,
new PropertyCondition(AutomationElement.ClassNameProperty, "Shell_TrayWnd"));
if (tray is null) return null;
var start = tray.FindFirst(TreeScope.Descendants,
new PropertyCondition(AutomationElement.AutomationIdProperty, "StartButton"))
?? tray.FindFirst(TreeScope.Descendants, new AndCondition(
new PropertyCondition(AutomationElement.NameProperty, "Start"),
new PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)));
if (start is null || start.Current.IsOffscreen) return null;
var r = start.Current.BoundingRectangle;
if (r.IsEmpty || r.Width <= 0 || r.Height <= 0) return null;
return start;
}
Two things that would help me confirm: is the failing runner using more than one display (or a virtual/headless one)? And what exact build is it on (winver)? The taskbar tree has shifted across 22H2/23H2/24H2, so the build matters.
If you found my response helpful or informative, I would greatly appreciate it if you could follow this guide for your confirmation.
Thank you.