As hard as we have been trying to convert our test automation scripts to UI-less automation, every so often we get backed into a corner and need to deal with a dialog which pops open at some point. An example of that is the "Spell Check Complete" dialog. Hit F7 in OneNote or Word or the like and, if you have no spelling errors on the page, you should very quickly get this dialog:

    clip_image001

    There is not a lot to this dialog. Just a frame named "Microsoft Office OneNote," an "OK" button, some text and an icon. What to do with our automation when this dialog opens seems equally simple: verify the dialog is indeed open and dismiss it.

    To complete those two tasks, the first thing I need to do is get a handle to this particular dialog. For those that don't write a lot of code, think of a handle like a street address. It's just a number. To get that number, I can use the FindWindow() command well documented at http://msdn.microsoft.com/en-us/library/ms633499.aspx. All I need is the name of the window, which in this case is "Microsoft Office OneNote." Our task library has a routine already to help. This is what it looks like:

    public static IntPtr FindWindowWithCaption()
    {

    string strCaption = "Microsoft Office OneNote";
    IntPtr hWnd = IntPtr.Zero;
    hWnd = GetForegroundWindow();

    while (hWnd != IntPtr.Zero)
    {
    //Get window caption
    String caption = //some uninteresting code to get the caption of the window handle

    //If caption text equals string, return handle
    if (caption.ToString().Equals(strCaption))
    {
    return hWnd;
    }

    //Get next window handle
    hWnd = GetWindow(hWnd, (uint)GwType.GW_HWNDNEXT);
    }

    return hWnd;

    }


    As far as code goes, this is pretty straightforward. It gets the number of the topmost window open first, then compares its title to "Microsoft Office OneNote." If the caption of the window matches, it sends me back the number. If not, it keeps looking through all the open windows one at a time to check to see if the caption matches.

    And the routine sort of worked for me. It would always find the spell check complete when it was open - great! But I also need to check the dismissal of the dialog, so I had to call the routine a second time to verify the dialog was gone after being dismissed. This second check failed. It took me an embarrassingly long time for me to find the bug - can you spot it more quickly?

    -------------------------------------------------------

    The problem occurred when the loop was in its last pass. At that point, hWnd was the number of the last window opened on screen. The code would check to see if the name of the caption was "Microsoft Office OneNote" and it would always not match - remember, the dialog was not open at this point, so it would never find a dialog with that name. Then the code would quit checking since it was at the end of examining all the windows, and return the number of the last window it had checked. Bingo! I decided to create a second temporary number and only set it to a value when the correct dialog was found, then return that value.

    Here's what I had:

    public static IntPtr FindWindowWithCaption(string strCaption)
    {

    IntPtr hWnd = IntPtr.Zero;
    IntPtr retVal = IntPtr.Zero;
    //…same as above

    while (hWnd != IntPtr.Zero)
    {

    //the same as above ...
    if (caption.ToString().Equals(strCaption))
    {
    retVal = hWnd;
    return retVal;
    }

    //Get next window handle
    hWnd = GetWindow(hWnd, (uint)GwType.GW_HWNDNEXT);

    }

    return retVal;

    }

    Now the code will properly return the number (handle) of the first window it finds named "Microsoft Office OneNote." And the second test I had now works properly.

    But from a test verification point of view, there is still a bug present. Can you find it? Hint: read the paragraph above one more time and think about other things that need to be verified, or other things that may not work as expected when spell check is complete.

    Questions, comments, concerns and criticisms always welcome,

    John