Get all window handles for a process
Solution 1
Pass IntPtr.Zero
as hWnd
to get every root window handle in the system.
You can then check the windows' owner process by calling GetWindowThreadProcessId
.
Solution 2
For everyone still wondering, this is the answer:
List<IntPtr> GetRootWindowsOfProcess(int pid)
{
List<IntPtr> rootWindows = GetChildWindows(IntPtr.Zero);
List<IntPtr> dsProcRootWindows = new List<IntPtr>();
foreach (IntPtr hWnd in rootWindows)
{
uint lpdwProcessId;
WindowsInterop.User32.GetWindowThreadProcessId(hWnd, out lpdwProcessId);
if (lpdwProcessId == pid)
dsProcRootWindows.Add(hWnd);
}
return dsProcRootWindows;
}
public static List<IntPtr> GetChildWindows(IntPtr parent)
{
List<IntPtr> result = new List<IntPtr>();
GCHandle listHandle = GCHandle.Alloc(result);
try
{
WindowsInterop.Win32Callback childProc = new WindowsInterop.Win32Callback(EnumWindow);
WindowsInterop.User32.EnumChildWindows(parent, childProc, GCHandle.ToIntPtr(listHandle));
}
finally
{
if (listHandle.IsAllocated)
listHandle.Free();
}
return result;
}
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;
}
for WindowsInterop:
public delegate bool Win32Callback(IntPtr hwnd, IntPtr lParam);
for WindowsInterop.User32:
[DllImport("user32.dll")]
public static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.Dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool EnumChildWindows(IntPtr parentHandle, Win32Callback callback, IntPtr lParam);
Now one can simply get every root window by GetRootWindowsOfProcess, and their children by GetChildWindows.
Solution 3
You can use EnumWindows
to get every top-level window, and then filter the results based on GetWindowThreadProcessId
.
Comments
-
Jeremy almost 2 years
Using Microsoft Spy++, I can see that the following windows that belong to a process:
Process XYZ window handles, displayed in tree form just like Spy++ gives me:
A B C D E F G H I J K
I can get the process, and the MainWindowHandle property points to the handle for window F. If I enumerate the child windows using I can get a list of window handles for G through K, but I can't figure out how to find the window handles for A through D. How can I enumerate windows that are not children of the handle specified by MainWindowHandle of the Process object?
To enumerate I'm using the win32 call:
[System.Runtime.InteropServices.DllImport(strUSER32DLL)] public static extern int EnumChildWindows(IntPtr hWnd, WindowCallBack pEnumWindowCallback, int iLParam);
-
Jeremy almost 14 yearsIs that the only way? Will try this. I wonder how time consuming this operation will be...
-
dudeNumber4 about 7 yearsNot just your example, but GetChildWindows simply doesn't work passing in Process.GetCurrentProcess().MainWindowHandle. I launch a child window (modally or not), call GetChildWindows, and the EnumWindow callback simply never fires.
-
dudeNumber4 about 7 yearsYou mean OS? Win8.
-
xamid about 7 yearsWIndows 8 is the problem.
-
dudeNumber4 about 7 yearsNo, just tried it on Win; same thing. This is one thing MS has always been good at; these API calls work the same across OSs.
-
xamid about 7 yearsI tried Win8 and it didn't work. They changed how the screen and handles work in Win8. But for Win7, it works for me (same notebook - I downgraded it after those problems). So there must be another reason why it doesn't work for you on Win7. It's not the OS.
-
dudeNumber4 about 7 yearsI wrote Win 10 (no space) above and it turned into a semicolon. So windows 10 doesn't work either.
-
MrLister almost 7 yearsWIndows 8 is the problem - how can it be done on windows 8 then?