Logging the contents of every message box dialog via automation


Today's Little Program logs the contents of every message box dialog, or anything that vaguely resembles a message box dialog. (Since there's no way for sure to know whether a dialog box is a message box or not.)

using System.Windows.Automation;

class Program
{
 [System.STAThread]
 public static void Main(string[] args)
 {
  Automation.AddAutomationEventHandler(
   WindowPattern.WindowOpenedEvent,
   AutomationElement.RootElement,
   TreeScope.Descendants,
   (sender, e) => {
    var element = sender as AutomationElement;
    if (element.GetCurrentPropertyValue(
     AutomationElement.ClassNameProperty) as string != "#32770") {
     return;
    }

    var text = element.FindFirst(TreeScope.Children,
     new PropertyCondition(AutomationElement.AutomationIdProperty, "65535"));
    if (text != null) {
     System.Console.WriteLine(text.Current.Name);
    }
   });
  System.Console.ReadLine();
  Automation.RemoveAllEventHandlers();
 }
}

This is the same pattern as the program we wrote last week, but with different guts when the window opens.

This time, we see if the class name is #32770, which UI Spy tells us is the class name for dialog boxes. (That this is the numerical value of WC_DIALOG is no coincidence.)

If we have a dialog, then we look for a child element whose automation ID is 65535, which UI Spy tells us is the automation ID for the text inside a message box dialog. (That the traditional control ID for static controls is -1 and 65535 is the the numerical value of (WORD)-1, is no coincidence.)

If so, then we print the text.

If we were cleverer, we could also confirm that the only buttons are OK, Cancel, and so on. Otherwise, we can get faked out by other dialog boxes that contain static text.

Comments (9)
  1. Dan Bugglin says:

    A little known feature is that you can press CTRL+C to copy the text of dialog boxes.

    Obviously it's bad form to hijack the clipboard and simulate key presses, so I wonder if there's a programmatic way to get the text that would be copied… or if you would just end up with approximately this little program anyway.

    [It would basically be this program, if you also added code to capture the button labels. -Raymond]
  2. John says:

    We use the UIAutomation Framework very heavily in our in house wrapper around it. I'm always happy to see Raymond give some input on it (the UIAutomation Library) we have a very similar function internally.

    One thing to be on the lookout for is enumerating from the AutomationElement.RootElement and asking for Descendants is usually going to result in you having a bad time if you've got a complex tree (it is remarked upon in the MSDN docs). Obviously this is a Toy program/Little Program so no real qualms there, just be on the look out for it.

    Only tangentially related does anyone know if these guys have their own blog? I was able to find the MSDN forum and they are pretty responsive there, but it'd be neat to know if they had a blog that showed best practices? We've run into issues were we consume 100% CPU in the AutomationElement.FindFirst() call. The core problem I believe is that we rely on heavily on polling and the assumption that FindFirst() is reasonably cheap (bad bad bad assumption). I noticed on Raymond's last blog post that he was able to register for Window events (which is usually the preferred solution), but have not researched it further.

    Long winded post/not the right forum, etc the tl;dr; I like seeing these programs as it exposes me to more real usage of the API, where can I find more?

  3. parkrrrr says:

    @John: there's blogs.msdn.com/…/winuiautomation but it's fairly low-traffic. The last post was in October.

  4. Myria says:

    I imagine that this wouldn't work on crash dialog message boxes, because those are owned by csrss.exe.

  5. But... says:

    Message boxes can have more than OK/Cancel – there are several buttons they can display – so testing for buttons would need to be a little more sophisticated. And there's the optional icon.

    Still, a little work, and it could be closer to correct :-)

  6. Neil says:

    Just send the window a WM_COPY message. Works in Windows XP at least.

  7. Michael says:

    How does this method compare with SetWinEventHook, as described here:

    blogs.msdn.com/…/10404940.aspx

  8. IInspectable says:

    @Neil: The clipboard belongs to the user. You have no business destroying it for them. Plus, this constitutes a Global Solution to a Local Problemâ„¢.

  9. parkrrrr says:

    @Michael: SetWinEventHook is part of the Active Accessibility API (MSAA). UI Automation was designed to replace MSAA, ideally fixing many of the shortcomings of the older framework along the way.

    Practically speaking, anything that implements MSAA is proxied to UIA. The reverse is also generally true, but only to the extent that the conversion is possible – UIA has much richer information than MSAA.

Comments are closed.