44

I have the handle for a given window. How can I enumerate its child windows?

Shog9
  • 156,901
  • 35
  • 231
  • 235
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142

5 Answers5

43

Here you have a working solution:

public class WindowHandleInfo
{
    private delegate bool EnumWindowProc(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr lParam);

    private IntPtr _MainHandle;

    public WindowHandleInfo(IntPtr handle)
    {
        this._MainHandle = handle;
    }

    public List<IntPtr> GetAllChildHandles()
    {
        List<IntPtr> childHandles = new List<IntPtr>();

        GCHandle gcChildhandlesList = GCHandle.Alloc(childHandles);
        IntPtr pointerChildHandlesList = GCHandle.ToIntPtr(gcChildhandlesList);

        try
        {
            EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
            EnumChildWindows(this._MainHandle, childProc, pointerChildHandlesList);
        }
        finally
        {
            gcChildhandlesList.Free();
        }

        return childHandles;
    }

    private bool EnumWindow(IntPtr hWnd, IntPtr lParam)
    {
        GCHandle gcChildhandlesList = GCHandle.FromIntPtr(lParam);

        if (gcChildhandlesList == null || gcChildhandlesList.Target == null)
        {
            return false;
        }

        List<IntPtr> childHandles = gcChildhandlesList.Target as List<IntPtr>;
        childHandles.Add(hWnd);

        return true;
    }
}

How to consume it:

class Program
{
    [DllImport("user32.dll", EntryPoint = "FindWindowEx")]
    public static extern IntPtr FindWindowEx(IntPtr hwndParent, IntPtr hwndChildAfter, string lpszClass, string lpszWindow);

    static void Main(string[] args)
    {
        Process[] anotherApps = Process.GetProcessesByName("AnotherApp");
        if (anotherApps.Length == 0) return;
        if (anotherApps[0] != null)
        {
            var allChildWindows = new WindowHandleInfo(anotherApps[0].MainWindowHandle).GetAllChildHandles();
        }
    }
}
OldBuildingAndLoan
  • 2,801
  • 4
  • 32
  • 40
Caffé
  • 1,161
  • 1
  • 9
  • 19
  • how can i get user32.dll ?? – jai May 28 '15 at 07:04
  • 1
    @jai It's a Windows library, it's already present and registered in your machine. That code should work without the need for additional references. – Caffé May 28 '15 at 15:27
  • thanks @caffe.... But actually if i use user32.dll , the application asking some kind of permission...where i can couldn't run the application...how can i resolve that... – jai May 29 '15 at 06:10
  • Pretty sure `GCHandle.FromIntPtr` cannot return null. – Drew Noakes Oct 10 '16 at 10:19
  • [pinvoke.net](http://pinvoke.net/default.aspx/user32.EnumChildWindows) is a great place for references to using the win API. – Josh Gust Aug 29 '18 at 16:35
12

Using:

internal delegate int WindowEnumProc(IntPtr hwnd, IntPtr lparam);

[DllImport("user32.dll")]
internal static extern bool EnumChildWindows(IntPtr hwnd, WindowEnumProc func, IntPtr lParam);

you will get callbacks on the function you pass in.

Grzenio
  • 35,875
  • 47
  • 158
  • 240
8

I've found the best solution to be Managed WindowsAPI. It had a CrossHair control that could be used to select a window(not part of the question), and a method AllChildWindows to get all child windows which likely wrapped the EnumChildWindows function. Better not to reinvent the wheel.

Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
7

Use EnumChildWindows, with p/invoke. Here's an interesting link about some of it's behavior: https://blogs.msdn.microsoft.com/oldnewthing/20070116-04/?p=28393

If you don't know the handle of the window, but only it's title, you'll need to use EnumWindows. http://pinvoke.net/default.aspx/user32/EnumWindows.html

Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
John Fisher
  • 22,355
  • 2
  • 39
  • 64
3

Here is a managed alternative to EnumWindows, but you will still need to use EnumChildWindows to find the handle of the child window.

foreach (Process process in Process.GetProcesses())
{
   if (process.MainWindowTitle == "Title to find")
   {
      IntPtr handle = process.MainWindowHandle;

      // Use EnumChildWindows on handle ...
   }
}
Special Touch
  • 476
  • 3
  • 15
  • I'm trying to do this, but there is no main window for the process. – Epu Oct 07 '11 at 14:47
  • 1
    Epu, if there is not a main window then the process will not have a window handle to obtain (ie. Process.MainWindowHandle == IntPtr.Zero). – Special Touch Oct 07 '11 at 21:31