Tuesday, April 03, 2007

FindWindowEx() does not always return child window controls

There was a task to control separate application via button clicks. We've created a small prototype, that can identify top-level window, and after that found necessary control inside this window using FindWindowEx. To my surprise it was not always working as I expected. Sometimes I was getting null instead of handle to the corresponding window. So I decided to create my own version of that method:


private static IntPtr WaitChild(IntPtr parent, string windowClass,
string windowCaption) {
IntPtr result = IntPtr.Zero;
do {
Thread.Sleep(10);
EnumChildWindows(parent, delegate(IntPtr hWnd, IntPtr lParam) {
StringBuilder className = new StringBuilder(200);
GetClassName(hWnd, className, 200);
StringBuilder caption = new StringBuilder(200);
GetWindowText(hWnd, caption, 200);
if (className.ToString() == windowClass &&
caption.ToString() == windowCaption)
result = hWnd;
return true;
}, IntPtr.Zero);
} while (result == IntPtr.Zero);
return result;
}

[DllImport("user32.dll")]
private static extern bool EnumChildWindows(IntPtr hwndParent,
EnumWindowsProc lpEnumFunc, IntPtr lParam);

private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll", SetLastError=true, CharSet=CharSet.Auto)]
private static extern int GetWindowText(IntPtr hWnd,
[Out] StringBuilder lpString, int nMaxCount);

[DllImport("user32.dll", CharSet=CharSet.Auto)]
private static extern int GetClassName(IntPtr hWnd,
StringBuilder lpClassName, int nMaxCount);

Sometimes it takes one or two loops while the window is finally appears on the screen, but it works pretty stable now

2 comments:

Dmitry Pavlov said...

Good catch. Thanks a lot!

Andrew Zaikin said...

Expect more stuff for HTML automation. TestComplete is resting in piece :)