以编程方式获取 Windows 应用程序的托盘菜单项

Programmatically obtaining a Windows application's tray menu items

我有一个带有托盘菜单的应用程序,我正在尝试自动执行一些涉及托盘菜单的测试。基本上我需要获取托盘菜单的项目并对它们进行处理。 但是,我只能找到以编程方式获取应用程序内菜单项的方法。但是我的自动化测试将是一个外部应用程序,所以这对我没有帮助。

如何以编程方式获取外部应用程序的托盘菜单项?

How can I obtain an external application's tray menu items programmatically?

你不能。没有 public API 提供对通知图标的访问。

有一些方法 enumerate/access 托盘图标本身(通常涉及连接到通知托盘本身,或使用 UI 自动化),但无法访问出现的弹出菜单单击托盘图标时。原因是因为图标所属的应用程序在点击发生时收到一条消息,然后采取相应的行动,这通常涉及显示其自己的弹出菜单。没有与图标本身关联的菜单。

对于您正在尝试的操作,您必须枚举图标并找出哪个图标属于您感兴趣的应用程序(这本身不是一项微不足道的任务),然后模拟点击图标,以便应用程序显示其弹出菜单。有关详细信息,请参阅以下问题:

Finding and simulating a click on a system tray icon?

一旦显示弹出菜单,与它的交互将变得更加困难。您将无权访问菜单本身。您可能不得不求助于通过 mouse_event()SendInput() 发出鼠标事件,将鼠标光标移动到菜单上并单击其项目(假设它们出现在相对于图标的可预测位置)。

如果可以获取图标的HWND+ID或者GUID(通过hook通知栏本身),可以使用Shell_NotifyIconGetRect()来至少得到图标的坐标。

根据您认为可接受的假设类型,您可以在任务栏按钮的菜单可见时以编程方式与其进行交互。下图显示了 OneNote 剪切工具按钮菜单上的 Inspect SDK 工具报告属性。 (并且菜单项表示它们支持 UIA Invoke Patten,因此它们应该可以通过 UIA 客户端代码以编程方式调用。)

如果您想调用托盘按钮的菜单项,您可以考虑使用 UIA 执行以下步骤。您可能会觉得我在这里所做的假设不适合您的情况。

  1. 找到名称为 class "NotifyIconOverflowWindow" 的元素,它是根菜单的直接子元素。我假设按钮在溢出区域。

  2. 枚举溢出元素的子元素,寻找与您的按钮同名的按钮。这假设 UI 语言是已知的并被解释。

  3. 获取按钮的bounding rect,模拟鼠标右键点击按钮。点击模拟是必要的,因为我敢打赌 UI 不支持 IUIAutomationElement3::ShowContextMenu(),(但您可以随时尝试)。

  4. 打开上下文菜单后,找到 ControlType 为 Menu、Name 为 "Context" 的元素,它是根元素的直接子元素。

  5. 获得菜单后,枚举菜单中的子元素以查找项,然后对它们执行您想要的操作。例如获取菜单项的调用模式并调用它。