通过手柄或pid获取儿童窗户的窗户

时间:2014-03-04 13:55:25

标签: c# winapi parent-child

我有主要过程/窗口的处理和pid 我想得到进程/窗口的子代 - 只有带标题的可视窗口。

为实现我的目标,我使用了以下内容:

[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;
}

其中_threadPid是父母的pid。

效果很好,但我觉得有更好的方法,而不是通过所有打开的窗口并过滤它们。

我是对的吗?我怎样才能做得更好?

我看到了关于EnumChildWindows的一些信息,但我也能做到这一点。

修改

基于Raymond陈的评论,我想通过说"孩子":来澄清我的意思  1.如果您打开便利贴并添加注释 - 便签是儿童  2.如果打开Paint.NET并按(f5,f6,f7,f8)打开面板      - 这些是儿童窗户 程序的每个窗口都不是主要的(对话框)我称之为儿童。

编辑2:

使用汉斯方法后,我的代码在这里:

[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);
   }
}

不需要使用GetWindowLongPtr,因为所有拥有的窗口必须具有标题并且可见其他我真的不在乎所以这些条件已经过滤了拥有的窗口。

1 个答案:

答案 0 :(得分:3)

显然,你实际上并没有谈论子窗口,EnumWindows()没有枚举它们。这些肯定是拥有的窗口,它们保持在它们的所有者之上,并在所有者最小化时被最小化。用于工具窗口和对话框,如Paint.NET使用。没有专用的winapi函数来枚举拥有的窗口。

您可以提高效率。枚举进程中的线程,使用Process.Threads。然后为每个线程使用EnumThreadWindows()。具有GWLP_HWNDPARENT的GetWindowLongPtr()返回所有者的句柄,如果它是拥有的窗口则为非零。