0

The EnumWindows and EnumChildWindows grab many many window handles. I just want the top most for each running process. A lot of them return 0 from within Process.GetProcesses(), what's the deal?

I've browsed around and tried the process.Refresh(); and had no good result. Also read through the other articles. How do you grab all of the Processes MainWindowHandle correctly?

Again: EnumWindows does not get only the main process handle, it grabs many for each process.

using System.Diagnostics;

Process[] p1 = Process.GetProcesses();
foreach (Process t in p1)
{
    listBox3.Items.Add(t.ProcessName + ": " + t.MainWindowHandle.ToString());
}
John Saunders
  • 160,644
  • 26
  • 247
  • 397
ploxtic
  • 273
  • 3
  • 4
  • 20
  • Can you share the code you already have? – rene Mar 16 '13 at 10:43
  • possible duplicate of [How to get main window handle from process id?](http://stackoverflow.com/questions/1888863/how-to-get-main-window-handle-from-process-id) – Cody Gray - on strike Mar 16 '13 at 10:49
  • nope, you'll have too many for each process. They never solved it correctly... it has no window handle from Process.MainWindowHandle.. it's 0; – ploxtic Mar 16 '13 at 10:52
  • [The real answer is hidden further down the page](http://stackoverflow.com/a/1889025/366904). Windows doesn't track a "main window" for each process. It has no way of knowing what an application considers its "main" window since an application can create multiple top-level windows. – Cody Gray - on strike Mar 16 '13 at 11:13
  • 1
    I have edited your title. Please see, "[Should questions include “tags” in their titles?](http://meta.stackexchange.com/questions/19190/)", where the consensus is "no, they should not". – John Saunders Mar 16 '13 at 11:37

2 Answers2

3

how do you find what window takes process ownership?

That's a misconception, surely the reason you are getting stuck. A window doesn't own a process, it is the other way around. And more subtly, a thread owns a window. And a process owns a thread.

When you use Process.GetProcesses() then you'll enumerate a lot of processes that do not have any window at all. Like all of the services that run on the machine, having dozens of them is not unusual. You can use Task Manager to see them in the Processes tab, be sure to click the option that shows processes owned by all users. SysInternals' Process Explorer is also a very nice tool to see what is running.

So don't be surprised that Process.MainWindowHandle returns IntPtr.Zero. And also keep in mind that it is a guess. A process can easily own multiple top-level windows. Which one of them is the "main" window isn't always obvious. The Process class uses a simple rule, it assumes that the first top-level window that it finds that doesn't have an owner and is visible is the main window.

To reliably get the top-level windows for a process you must first enumerate the threads in the process. Easy to do with Process.Threads. Then for each thread, you iterate the windows it owns by pinvoking EnumThreadWindows(). Exact same idea as EnumWindows() but limited to the specific thread and without the firehose problem and lower odds that it falls apart because a new window got created while you were iterating. You'll get the top-level windows owned by the thread, what you want, enumerating the child windows owned by each top-level window requires EnumChildWindows().

Some notable bad news: do note that some filtering is required to get decent results. A thread very commonly owns a window that's not visible at all. Commonly used to take care of inter-thread communication, particularly common for code that uses COM. So you probably also want to pinvoke IsWindowVisible(). And always check for errors on these pinvoked functions, failure is common when your program isn't running with admin privileges and/or is not UAC elevated. Always double-check your results by what you see from the Spy++ utility.

Hans Passant
  • 922,412
  • 146
  • 1,693
  • 2,536
  • How do you know that Process.MainWindowHandle guesses the first top-level window a process created is its main window? I tried looking at the code in Reflector. I see the callback function calls another internal helper function, IsMainWindow. That one calls GetWindow to check for GW_OWNER and IsWindowVisible. I don't see anything that checks the creation time or order--I didn't even know such a thing was possible. (Great explanation in this answer, by the way!) – Cody Gray - on strike Mar 17 '13 at 06:19
0

If you read the documentation for MainWindowHandle, you'll see the following note:

If the associated process does not have a main window, the MainWindowHandle value is zero. The value is also zero for processes that have been hidden, that is, processes that are not visible in the taskbar. This can be the case for processes that appear as icons in the notification area, at the far right of the taskbar.

Bear in mind that it corresponds to the handle of top-most window, it's not really the "Main Window Handle", you're probably better off using manual enumeration in that case.

Anya Shenanigans
  • 91,618
  • 3
  • 107
  • 122