2
votes

I'm trying to get the handle of a child dialog window. I've tried using FindWindowEx, but it didn't work. Instead, FindWindow did work.

I did an experiment with visual studio's options window, with the following code:

IntPtr vsHandle = Process.GetProcessById(vsProcessId).MainWindowHandle; // consistent with spy++'s parent handle of options window

IntPtr optionsHandle = FindWindowEx(vsHandle, IntPtr.Zero, "#32770", "Options"); // returns 0

IntPtr optionsHandle2 = FindWindow("#32770", "Options"); // returns correct handle

From my understanding, FindWindowEx should've worked, it is a child window.

I'm running windows xp, and have also tried using FindWindowEx(vsHandle, IntPtr.Zero, "#32770", null). Didn't work. Seems like the only way to get it is using FindWindow which isn't good enough as two parent instances with the same dialog can be open.

This is the declaration:

[DllImport("user32.dll")]
Private static extern IntPtr FindWindow(string className, string windowTitle);
[DllImport("user32.dll")]
Private static extern IntPtr FindWindowEx(IntPtr parentHWnd, IntPtr childAfterHWnd,     string className, string windowTitle);

Thanks in advance.

1
try EnumWindows() instead.David
but @David, EnumWindows - Enum top-level, not child, exept top-level owned by the system that have the WS_CHILD style (see MSDN)...kero
@Rita, FindWindowEx of course can find and really find every child window. For example, if you run exe from files.rsdn.ru/42164/wintreesnap.zip with parametr _f - you'll get text file with full window tree namely via FindWindowEx. Look for errors in your code...kero
EnumWindows uses callbacks, and it can not only search top level windows, but all the child windows of a given HWND, see also msdn.David
@David, then - why not via EnumChildWindows(GetDesktopWindow), easier and faster, see msdn :) Btw, Rita asked about FindWindowEx.kero

1 Answers

6
votes

I found a solution to this. The reason FindWindowEx didn't work was because it only works on child windows that have WS_CHILD style, and apparently dialog windows do not have this style. It is why EnumChildWindows won't work either (I've tried).

So the ugly solution is EnumWindows combined with GetParent to compare the handle and the text.

        struct SearchData
        {
            public string WindowText;
            public IntPtr ParentHandle;
            public IntPtr ResultHandle;
        }

        delegate bool EnumWindowsCallback(IntPtr currentWindowHandle, ref SearchData searchData);

        [DllImport("user32.dll")] static extern bool EnumWindows(EnumWindowsCallback callback, ref SearchData searchData);

        [DllImport("user32.dll")] static extern IntPtr GetParent(IntPtr childHandle);

        [DllImport("user32.dll")] static extern void GetWindowText(IntPtr handle, StringBuilder resultWindowText, int maxTextCapacity);


        static bool Callback(IntPtr currentWindowHandle, ref SearchData searchData)
        {
            bool continueEnumeration = true;

            IntPtr currentWindowParentHandle = GetParent(currentWindowHandle);

            if (currentWindowParentHandle == searchData.ParentHandle)
            {
                var windowText = new StringBuilder(1024);
                GetWindowText(currentWindowHandle, windowText, windowText.Capacity);

                if (windowText.ToString() == searchData.WindowText)
                {
                    searchData.ResultHandle = currentWindowHandle;
                    continueEnumeration = false;
                }
            }

            return continueEnumeration;
        }


        IntPtr GetChildWindowHandle(string windowText, IntPtr parentHandle)
        {
            var searchData = new SearchData{ParentHandle=parentHandle, WindowText=windowText};

            EnumWindows(Callback, ref searchData);

            return searchData.ResultHandle;
        }