简体   繁体   中英

Programmatically obtaining a Windows application's tray menu items

I have an application with a tray menu and I'm trying to automate some tests that involve the tray menu. Basically I need obtain the tray menu's items and do stuff with them. However, I've only been able to find ways to programmatically obtain menu items for within the application. But my automation tests are going to be an external application, so that doesn't help me.

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

There are ways to enumerate/access the tray icons themselves (usually involving hooking into the notification tray itself, or using UI Automation), but there is no way to access a popup menu that appears when a tray icon is clicked on. The reason is because the icon's owning application receives a message when the click occurs and then acts accordingly, which usually involves displaying its own popup menu. There is no menu associated with the icon itself.

For what you are attempting, you would have to enumerate the icons and figure out which icon belongs to the app you are interested in (not a trivial task on its own), then simulate a click on the icon so the app displays its popup menu. See the following question for some details:

Finding and simulating a click on a system tray icon?

Interacting with the popup menu once it is displayed will be more difficult. You won't have access to the menu itself. You will likely have to resort to just issuing mouse events via mouse_event() or SendInput() to move the mouse cursor over the menu and click its items (assuming they appear in predictable locations relative to the icon).

If you can obtain the icon's HWND+ID or GUID (by hooking the notification tray itself), you can use Shell_NotifyIconGetRect() to get the icon's coordinates, at least.

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

You cannot. There is no public API that provides access to notification icons.

Depending on what sort of assumptions you find acceptable, you can programmatically interact with the taskbar button's menu once it's visible. The image below shows the Inspect SDK tool reporting properties on the OneNote clipping tool button's menu. (And the menu items say they support the UIA Invoke Patten, so they should be programmatically invokable by UIA client code.)

If you want to invoke your tray button's menu items, you might consider the following steps using UIA. You may feel the assumptions that I make here are unacceptable for your situation.

  1. Find the element with a class name "NotifyIconOverflowWindow", that's a direct child of the root menu. I'm assuming the button is in the overflow area.

  2. Enumerate the children of the overflow element, looking for a button with the name of your button. This assumes the UI language is known and accounted for.

  3. Get the bounding rect of the button and simulate a mouse right-click on the button. The click simulation is necessary because I'll bet the UI doesn't support IUIAutomationElement3::ShowContextMenu(), (but you could always try it).

  4. Once the context menu's up, find the element with a ControlType a Menu, a Name of "Context", that's a direct child of the root element.

  5. Once you have the menu, enumerate the child elements in the menu to find the items, and do what you want with them. Eg get the menu item's Invoke pattern and invoke it.

在此处输入图片说明

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM