February 19, 2009

View System Windows – Windows and Objects

Filed under: Automation,Scripting — Marcus Tettmar @ 10:12 am

syswindows1

Macro Scheduler has a “View System Windows” tool which you can get to from the Tools menu. This displays a tree of all windows, their child windows and objects open in the system. For each entity you see its handle, class name and title/caption text.

The help file talks about windows and child windows. For windows you can read “objects”. In Windows a “windows control” is not necessarily a window in the sense that you are familiar with but could be a button, a status bar or edit box, or pretty much anything else you see inside a window or on the screen.

So the View System Windows tool shows the hierarchy of “windows” that currently exist on your system. You can expand one to see it’s child windows/objects and so on.

In the picture above I have highlighted the entry for what is commonly referred to as the “System Tray”. Its official title is “Notification Area”. If we right click this entry and select “Identify” a border will be drawn around the system tray icon area. This “Identify” option is a useful way to help locate a window or object and be sure that the entry you see in the list is the object you’re looking for.

A word about handles. These are the numbers that appear in the list. In the above snapshot the notification area has a handle of 131104. It will be different on your system. It will be different after you reboot. Handles are simply identification numbers that are allocated at run time when a window is first created by the system. So don’t go thinking you can grab that number and put it in your script and use it to identify your window. Next time you reboot the script won’t work.

After the handle you will see the “class name”. For the system tray this is “ToolbarWindow32”. This is static but not unique. It is just the type of object – the object class – that is used. We can use this to find an object, but it is not unique.

Macro Scheduler has a function called GetControlText which takes a window title (or handle), a class name and an index. This will return the text associated with an object of the specified class and index on the specified window. If there were two objects of that class an index of 1 would return the first and an index of 2 the second, in the order of creation (some trial and error is usually required). GetControlText is great for objects on regular windows and makes life simple. But for objects deeper in the hierarchy we might have to be a bit more clever.

Some objects also have captions and these are displayed after the class name. Here we see it is “Notification Area”. E.g. windows have captions and we’re used to seeing these in the title bar. Button objects have captions that appear on the button. Some other objects also have captions although they may not be visible (equally what you see on an object is not necessarily the caption that appears in the tree). If we have a caption we can also use this to help us find an object. If we don’t we would have to rely on indexes as in GetControlText – iterate through each instance of an object.

As an example, the following code gets us the handle of the system tray:

LibFunc>User32,FindWindowA,h1,Shell_TrayWnd,
LibFunc>User32,FindWindowExA,h2,h1,0,TrayNotifyWnd,
LibFunc>User32,FindWindowExA,h3,h2,0,SysPager,
LibFunc>User32,FindWindowExA,h4,h3,0,ToolbarWindow32,Notification Area

This code mirrors the hierarchy we see in the View System Windows tree above.

FindWindow takes a class name and caption to return a top level window. So this gives us the handle of the parent Shell_TrayWnd object. FindWindowEx finds an object on the given parent window. So the second line above looks for an object with class “TrayNotifyWnd” on the Shell_TrayWnd window (h1 returned by FindWindow) with no caption. It looks for the first match since the “child after” handle is set to zero. The next two lines continue to walk the tree. What we end up with in h4 is the handle of the system tray.

I use this code here in Activating System Tray Icons.

If all this sounds rather complicated, don’t worry. Most of us will never use code like this. I just wanted to explain more about what View System Windows shows us. There are much easier ways of identifying objects and scraping text from the screen that work in a much more human like way. Objects can be identified visually with Image Recognition and the Text Capture functions let us screen scrape by just specifying a window title or screen area. And most of the time we can automate a window by sending keystrokes to it and never have to care what an object is called.