I have handle and pid of main process / window.
I want to get the children of the process / window - only the visual windows with title.
to achieve what I want, I used the following:
[DllImport("user32.dll")] private static extern int EnumWindows(EnumWindowsProc ewp, int lParam);
[DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")] private static extern bool IsWindowVisible(int hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
public delegate bool EnumWindowsProc(int hWnd, int lParam); //Delegate used for EnumWindows() callback function.
public void GetChildren()
{
//Declare a callback delegate for EnumWindows() API call.
EnumWindowsProc ewp = new EnumWindowsProc(EvalWindow);
//Enumerate all Windows.
EnumWindows(ewp, 0);
}
//EnumWindows CALLBACK function
private bool EvalWindow(int hWnd, int lParam)
{
//Get the ThreadProcessId of the Window.
IntPtr handle = (IntPtr)hWnd;
uint currentThreadPid;
GetWindowThreadProcessId(handle, out currentThreadPid);
//Check if the Window is children of the current Window (if it is, it will have the same pid).
if (currentThreadPid != _threadPid)
return true;
//Check if Window is Visible or not.
if (!IsWindowVisible(hWnd))
return true;
//Get the Window's Title.
StringBuilder title = new StringBuilder(256);
GetWindowText(hWnd, title, 256);
//Check if Window has Title.
if (title.Length == 0)
return true;
//Add new Window to the _childrenhWnd.
_childrenhWnd.Add(handle);
return true;
}
where _threadPid
is the pid of the parent.
It works great but I feel there's a better way of doing it instead of going through all the opened windows and filter them.
Am I right? how can I do it better?
I saw something about EnumChildWindows
but I could achieve the same.
EDIT:
Based on RaymondChen comment, I want to clarify what I mean by saying "children":
1. If you open sticky notes and add notes - the notes are children.
2. If you open Paint.NET and press (f5, f6, f7, f8) to open the panels
- these are child windows.
Every window of the program which is not the main (dialogs also) I call children.
EDIT 2:
Here's my code after applying Hans's method:
[DllImport("user32.dll")] static extern bool EnumThreadWindows(int dwThreadId, EnumThreadDelegate lpfn, IntPtr lParam);
[DllImport("user32.dll")] private static extern bool IsWindowVisible(int hWnd);
[DllImport("user32.dll", CharSet = CharSet.Auto)] private static extern int GetWindowText(int hWnd, StringBuilder title, int size);
delegate bool EnumThreadDelegate(IntPtr hWnd, IntPtr lParam);
public void GetChildren()
{
foreach (ProcessThread processThread in _process.Threads)
{
EnumThreadWindows(processThread.Id,
(hWnd, lParam) =>
{
//Check if Window is Visible or not.
if (!IsWindowVisible((int)hWnd))
return true;
//Get the Window's Title.
StringBuilder title = new StringBuilder(256);
GetWindowText((int)hWnd, title, 256);
//Check if Window has Title.
if (title.Length == 0)
return true;
_childrenhWnd.Add(hWnd);
return true;
}, IntPtr.Zero);
}
}
didnt need to use GetWindowLongPtr
because all the owned windows must have title and be visible else I dont really care so these conditions already filter the owned windows.