Getting the Handle to a MessageBox that does not have a Caption using P/Invoke

Recently I’ve been working with some UI automation. A task I had to perform was getting the handle to a MessageBox that does not have a caption. The caption of a MessageBox is the mini-title part. The message part of a MessageBox is actually the caption of a child window. Anyway, the solution was to first get the handle to the Desktop. Using that handle, you can get the handles to all top level windows, including MessageBox windows. Each of these children can be checked to see if they have no caption. From this list of top level windows (typically MessageBox items and applications) that have no caption, you can examine their children to see if some target message text is there.

Calling this code looks like:

Console.WriteLine("\nGet a handle to an uncaptioned MsgBox");
IntPtr hForm = FindWindow(null, "Form1");
IntPtr hFormOK = FindWindowEx(hForm, IntPtr.Zero, null, "OK");


IntPtr hUncaptionedMsgBox =
  GetHandleToUncaptionedMsgBox("msgbox with no caption");
IntPtr hOkButton =
  FindWindowEx(hUncaptionedMsgBox, IntPtr.Zero, null, "OK");


The primary method is:

static IntPtr GetHandleToUncaptionedMsgBox(string text)
  // the text is the message part of a MsgBox
  // the caption is the title part of a MsgBox
  List allTopLevelWindowsWithNoCaption =
  for (int i = 0; i < allTopLevelWindowsWithNoCaption.Count; ++i)
    IntPtr hTopLevel = allTopLevelWindowsWithNoCaption[i];
    List children =
      GetAllChildrenWindowHandles(hTopLevel, 1000);
    for (int j = 0; j < children.Count; ++j)
      string s = GetControlText(children[j]);
      if (s == text) return hTopLevel;
  return IntPtr.Zero;

The method calls helpers GetTopLevelWidowsWithNoCaption and GetAllChildrenWindowHandles and GetControlText.

Method GetTopLevelWidowsWithNoCaption is:

static List GetTopLevelWidowsWithNoCaption()
  List result = new List();
  IntPtr hDesktop = GetDesktopWindow();
  List allTopLevelWindows =
    GetAllChildrenWindowHandles(hDesktop, 1000);
  for (int i = 0; i < allTopLevelWindows.Count; ++i)
    IntPtr hChild = allTopLevelWindows[i];
    string txt = GetControlText(hChild);
    if (txt == null)
  return result;

The helper calls GetDesktopWindow which is a P/Invoke function:

[DllImport("user32.dll", EntryPoint="GetDesktopWindow")]
static extern IntPtr GetDesktopWindow();

Method GetAllChildrenWindowHandles is:

static List GetAllChildrenWindowHandles(IntPtr hParent,
  int maxChildrenPerParent)
  List result = new List();
  int ct = 0;
  IntPtr prevChild = IntPtr.Zero;
  IntPtr currChild = IntPtr.Zero;
  while (true && ct < maxChildrenPerParent)
    currChild = FindWindowEx(hParent, prevChild, null, null);
    if (currChild == IntPtr.Zero) break;
    prevChild = currChild;
  return result;

I’ve explained other hewlpers in previous blog posts: FindWindowEx, GetControlText, FindWindow, and ClickOn. This was an interesting journey into P/Invoke land again. As I’ve mentioned several times, I most often work with machine learning algorithms but I like to keep in practice with low level programming too.


This entry was posted in Software Test Automation. Bookmark the permalink.