40

How i can find all the windows created by a particular process using c#?

UPDATE

i need enumerate all the windows belonging to an particular process using the PID (process ID) of the an application.

SqlRyan
  • 33,116
  • 33
  • 114
  • 199
Salvador
  • 16,132
  • 33
  • 143
  • 245

3 Answers3

101
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);

[DllImport("user32.dll")]
static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn,
    IntPtr lParam);

static IEnumerable<IntPtr> EnumerateProcessWindowHandles(int processId)
{
    var handles = new List<IntPtr>();

    foreach (ProcessThread thread in Process.GetProcessById(processId).Threads)
        EnumThreadWindows(thread.Id, 
            (hWnd, lParam) => { handles.Add(hWnd); return true; }, IntPtr.Zero);

    return handles;
}

and sample usage:

private const uint WM_GETTEXT = 0x000D;

[DllImport("user32.dll", CharSet = CharSet.Auto)]
static extern IntPtr SendMessage(IntPtr hWnd, uint Msg, int wParam, 
    StringBuilder lParam);

[STAThread]
static void Main(string[] args)
{
    foreach (var handle in EnumerateProcessWindowHandles(
        Process.GetProcessesByName("explorer").First().Id))
    {
        StringBuilder message = new StringBuilder(1000);
        SendMessage(handle, WM_GETTEXT, message.Capacity, message);
        Console.WriteLine(message);
    }
}
Konstantin Spirin
  • 20,609
  • 15
  • 72
  • 90
  • 4
    Thanks for posting this one! I'm seeing way better performance with this approach ("scan processes" -> "scan threads" -> "scan windows" as opposed to "scan windows" -> "check process id") – Marcus Apr 26 '14 at 06:29
  • This code will bring you so much pain debugging it, when your app crushes with a stack-based buffer overrun. Before passing list of handles to the unmanaged callback, you must pin the object with GCHandle. If you don't to this and race condition will take place, your list will be moved - app will silently crush – Toddams Jan 17 '20 at 15:26
  • 2
    @Toddams in this code list of handles does **not** get passed to the unmanaged callback. Instance of `EnumThreadDelegate` callback will be automatically pinned for the duration of each `EnumThreadWindows` call and this callback won't be needed afterwards so I don't think GC can cause any harm in this particular case. Your comment is generally valid only for truly asynchronous scenarios. https://learn.microsoft.com/en-us/dotnet/framework/interop/marshaling-a-delegate-as-a-callback-method – Konstantin Spirin Jan 19 '20 at 10:32
  • I'm pretty sure you should be disposing of those `Process` and `ProcessThread` objects. – Miroslav Policki Apr 10 '20 at 14:09
  • Disposing is not necessary for managed objects. The garbage collector does that alone. Dispose() is only required if you want to free much memory immediatley. For example if you are working with huge Bitmap's which consume Megabytes of memory and you want to free the memory immediately. Or you can Dispose() if you want to assure that a FileStream or a COM port is closed immediately. Otherwise the garbage collector does that when it has idle time. – Elmue Jul 29 '20 at 02:38
  • Based on your code I wrote an application that allows filtering the list of all open windows and brings the selected window to the front: [activatewindow](https://github.com/mardukbp/activatewindow) Thanks! – Marduk Oct 14 '20 at 09:05
  • @Elmue The garbage collector does not call `Dispose`. It calls the finalizer if one is present, and the finalizer typically calls a `Dispose` method. Not every class that implements `IDisposable` has a finalizer though, because having one is additional overhead. And relying on the GC to call finalizers instead of calling `Dispose` yourself will make you have more and longer collections, and thus worse performance. So generally, if something is `IDisposable`, you should dispose of it as soon as you don't need it anymore. – Miroslav Policki May 18 '22 at 08:20
  • I see that basic .NET knowledge is lacking here. Normally Dispose() and Finalizer call the same method which frees memory and resources. A finalizer is only required if UNMANAGED resources (e.g. Win32 HANDLE's) or UNMANAGED memory is used by the class. The performance is not affected. The CPU has to do exactly the same work if you immediately Dispose() or if the GC does this in a background thread when the app is idle. There is no overhead. The only difference is the moment when cleanup is done. But it must be done in both cases. The GC is highly optimized. – Elmue May 18 '22 at 14:18
19

Use the Win32 API EnumWindows (if you want child windows EnumChildWindows)), or alternatively you can use EnumThreadWindows .

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool EnumWindows(EnumThreadWindowsCallback callback, IntPtr extraData);

Then check which process each window belongs to by using the Win32 API GetWindowThreadProcessId

[DllImport("user32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetWindowThreadProcessId(HandleRef handle, out int processId);
Brian R. Bondy
  • 339,232
  • 124
  • 596
  • 636
  • 3
    Hmm, this enumerates the windows per thread. It requires a little more work to find the windows per process. See [Konstantin's answer below](http://stackoverflow.com/a/2584672/111575). – Abel Apr 01 '12 at 23:46
  • 2
    Better use Konstantin's answer! – Andrei Rînea Oct 03 '13 at 11:14
5

Ancient thread, but it got me started so here's a small utility function that will find a child window that matches a lambda (Predicate). Be easy to change to return a list. Multiple criteria are handled in the predicate.

    public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);

    [DllImport("user32.Dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);

    /// <summary>
    /// Find a child window that matches a set of conditions specified as a Predicate that receives hWnd.  Returns IntPtr.Zero
    /// if the target window not found.  Typical search criteria would be some combination of window attributes such as
    /// ClassName, Title, etc., all of which can be obtained using API functions you will find on pinvoke.net
    /// </summary>
    /// <remarks>
    ///     <para>Example: Find a window with specific title (use Regex.IsMatch for more sophisticated search)</para>
    ///     <code lang="C#"><![CDATA[var foundHandle = Win32.FindWindow(IntPtr.Zero, ptr => Win32.GetWindowText(ptr) == "Dashboard");]]></code>
    /// </remarks>
    /// <param name="parentHandle">Handle to window at the start of the chain.  Passing IntPtr.Zero gives you the top level
    /// window for the current process.  To get windows for other processes, do something similar for the FindWindow
    /// API.</param>
    /// <param name="target">Predicate that takes an hWnd as an IntPtr parameter, and returns True if the window matches.  The
    /// first match is returned, and no further windows are scanned.</param>
    /// <returns> hWnd of the first found window, or IntPtr.Zero on failure </returns>
    public static IntPtr FindWindow(IntPtr parentHandle, Predicate<IntPtr> target) {
        var result = IntPtr.Zero;
        if (parentHandle == IntPtr.Zero)
            parentHandle = Process.GetCurrentProcess().MainWindowHandle;
        EnumChildWindows(parentHandle, (hwnd, param) => {
            if (target(hwnd)) {
                result = hwnd;
                return false;
            }
            return true;
        }, IntPtr.Zero);
        return result;
    }

Example

var foundHandle = Win32.FindWindow(IntPtr.Zero, ptr => Win32.GetWindowText(ptr) == "Dashboard");
Wade Hatler
  • 1,785
  • 20
  • 18
  • With this you can do your job in the delegate, no need to return the HWND anymore. – jw_ Nov 23 '19 at 03:27