Windows UI自动化无法识别按钮控件

Ele*_*ios 11 .net vb.net ui-automation

我在尝试通过Windows UI Automation识别Notification Area窗口(classname:ToolbarWindow32)中的按钮控件时遇到问题:

在此输入图像描述

我通过Windows SDK中部署的Windows UI自动化工具验证了那些"图标"是类型的控件,但是当我尝试运行下面的代码时,我得到一个空引用异常,因为我使用的搜索条件没有得到任何控制.ControlType.Button

我做错了,或者我在Windows UI Automation中发现了某些限制?

这是代码,我将它与WinAPI调用混合,只是为了帮助那些可能会使用该方法的帮助用户.

Dim tskBarClassName As String = "Shell_TrayWnd"
Dim tskBarHwnd As IntPtr = NativeMethods.FindWindow(tskBarClassName, Nothing)

Dim systrayBarClassName As String = "TrayNotifyWnd"
Dim systrayBarHwnd As IntPtr = NativeMethods.FindWindowEx(tskBarHwnd, IntPtr.Zero, systrayBarClassName, Nothing)

Dim ntfyBarClassName As String = "ToolbarWindow32"
Dim ntfyBarHwnd As IntPtr = NativeMethods.FindWindowEx(systrayBarHwnd, IntPtr.Zero, ntfyBarClassName, Nothing)

Dim window As AutomationElement = AutomationElement.FromHandle(ntfyBarHwnd)
Dim condition As New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button)
Dim button As AutomationElement = window.FindFirst(TreeScope.Descendants, condition)

MsgBox(button.Current.Name) ' Here throws the null-reference exception.
Run Code Online (Sandbox Code Playgroud)

对此有何解决方案?

Çöđ*_*xěŕ 4

我通过 Windows SDK 中部署的 Windows UI 自动化工具验证这些“图标”是 ControlType.Button 类型的控件

你说得有点对。从技术上讲,它们不在 ToolbarWindow32 中,而是在 Shell_TrayWnd 中。我检查了该区域,发现这些按钮实际上位于 a 中ToolBar,因此您需要查找ControlType.ToolBar. 接下来,您需要FindAll返回所有满足以下条件的 AutomationElementsPropertyCondition...的 AutomationElements

注意:第一个循环是获取用户升级通知区域。下一个有趣的循环是获取正在运行的应用程序按钮...(代码适用于 WIN7、WIN8 和 WIN10)

在下面的示例中,我会寻找 它将Shell_TrayWnd为我们提供我们需要的东西。然后我遍历并找到ToolBar我们想要的内容,然后循环遍历...FindAll的 ControlTypesButton

Dim arrText As New List(Of String)
        Dim tskBarClassName As String = "Shell_TrayWnd"
        Dim tskBarHwnd As IntPtr = FindWindow(tskBarClassName, Nothing)
        Dim window As AutomationElement = AutomationElement.FromHandle(tskBarHwnd)
        Dim condition As New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.ToolBar)
        Dim elementCollection As AutomationElementCollection = window.FindAll(TreeScope.Descendants, condition)

        'for fun get all we can...
        For Each aE As AutomationElement In elementCollection
            If aE.Current.Name.Equals("User Promoted Notification Area") Then
                For Each ui As AutomationElement In aE.FindAll(TreeScope.Descendants, New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button))
                    arrText.Add("Notification Area - " & Replace(ui.Current.HelpText, Chr(10), " "c)) 'removed line break as when shown it would show some on a new line in messagebox
                Next
            ElseIf aE.Current.Name.Equals("Running applications") Then
                For Each ui As AutomationElement In aE.FindAll(TreeScope.Descendants, New PropertyCondition(AutomationElement.ControlTypeProperty, ControlType.Button))
                    arrText.Add("Toolbar Area - " & Replace(ui.Current.Name, Chr(10), " "c)) 'removed line break as when shown it would show some on a new line in messagebox
                Next
            End If

        Next

If arrText.Count > 0 Then
            MessageBox.Show(String.Join(Environment.NewLine, arrText.ToArray))
        End If
Run Code Online (Sandbox Code Playgroud)

如果您有任何疑问,请告诉我。下图(出于安全原因我注释掉了一些内容)

在此输入图像描述

  • 感谢您的回答,我想指出的是,所提供的解决方案不适用于非英语 Windows,因为代码中硬编码了英语本地化名称,那么也许更好的解决方案是比较类名(**ToolbarWindow32 **,**MSTaskListWClass**),这至少对我有用。 (2认同)