Saturday, February 19, 2011

Enumerating Windows/Controls of another application from .Net

I'm developing a small utility application that needs to detect whether another one has one of its MDI child windows open (it's an off-the-shelf Win32 business application over which I have neither source code nor control). From my app, I would like to be able to poll or detect when a particular MDI Child window is open.

In .Net, it's easy to iterate over running processes, but I haven't found an easy way to iterate through the (sub)windows and controls of a given Win32 process from .Net.

Any ideas?

Update
Thanks for the answers they got me on the right path.
I found an article with a test project that uses both EnumWindowsand EnumChidWindows and other API calls to get extended information on controls.

From stackoverflow
  • You can use P/Invoke to access EnumWindows and EnumChidWindows to itereate through the subwindows/controls of any window.

  • You must use native Win32 API.

    EnumChildWindows (user32)

    [DllImport("user32")]
    
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumChildWindows(IntPtr window, EnumWindowProc callback, IntPtr i);
    
    /// <summary>
    /// Returns a list of child windows
    /// </summary>
    /// <param name="parent">Parent of the windows to return</param>
    /// <returns>List of child windows</returns>
    public static List<IntPtr> GetChildWindows(IntPtr parent)
    {
    List<IntPtr> result = new List<IntPtr>();
    GCHandle listHandle = GCHandle.Alloc(result);
    try
    {
        EnumWindowProc childProc = new EnumWindowProc(EnumWindow);
        EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
    }
    finally
    {
        if (listHandle.IsAllocated)
        listHandle.Free();
    }
    return result;
    }
    
    /// <summary>
    /// Callback method to be used when enumerating windows.
    /// </summary>
    /// <param name="handle">Handle of the next window</param>
    /// <param name="pointer">Pointer to a GCHandle that holds a reference to the list to fill</param>
    /// <returns>True to continue the enumeration, false to bail</returns>
    private static bool EnumWindow(IntPtr handle, IntPtr pointer)
    {
    GCHandle gch = GCHandle.FromIntPtr(pointer);
    List<IntPtr> list = gch.Target as List<IntPtr>;
    if (list == null)
    {
        throw new InvalidCastException("GCHandle Target could not be cast as List<IntPtr>");
    }
    list.Add(handle);
    //  You can modify this to check to see if you want to cancel the operation, then return a null here
    return true;
    }
    
    /// <summary>
    /// Delegate for the EnumChildWindows method
    /// </summary>
    /// <param name="hWnd">Window handle</param>
    /// <param name="parameter">Caller-defined variable; we use it for a pointer to our list</param>
    /// <returns>True to continue enumerating, false to bail.</returns>
    public delegate bool EnumWindowProc(IntPtr hWnd, IntPtr parameter);
    

0 comments:

Post a Comment