C#获取桌面所有窗口句柄:GetDesktopWindow与GetWindow实战

桃夭
桃夭
发布时间:2026-10-13 | 3人浏览过
原创

在C#开发中,有时需要获取当前屏幕上的所有窗口列表。本文将演示如何调用Windows原生API,通过GetDesktopWindow获取桌面窗口句柄,并结合GetWindow函数的GW_CHILD参数遍历所有顶层子窗口。

了解关键Windows API

要实现窗口句柄的获取,主要涉及两个位于user32.dll中的核心函数:

1. GetDesktopWindow

作用:返回桌面窗口(即覆盖整个屏幕的背景窗口)的句柄。它是获取所有其他窗口的基础入口点。

关键点:无需传入参数,直接返回一个IntPtr类型的句柄。

2. GetWindow

作用:获取与指定窗口存在特定关系(如Z序、父子关系、所有者关系等)的窗口句柄。

参数说明:

  • hWnd: 参考窗口的句柄。
  • uCmd: 关系类型标识。例如使用GW_CHILD可获取第一个子窗口,使用GW_HWNDNEXT可获取下一个兄弟窗口。

注意:在处理复杂窗口树时,EnumChildWindows通常比GetWindow更安全,但在仅获取顶层可见窗口时,GetWindow结合循环是简洁有效的方案。

C#代码实现步骤

第1步:引入DLL并声明API函数

首先需要在类中引入System.Runtime.InteropServices命名空间,并使用[DllImport]特性导入user32.dll中的函数。

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;

public partial class MainForm : Form
{
    // 声明GetDesktopWindow,返回桌面窗口句柄
    [DllImport("user32.dll", EntryPoint = "GetDesktopWindow", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetDesktopWindow();

    // 声明GetWindow,用于获取相关窗口句柄
    [DllImport("user32.dll", SetLastError = true)]
    private static extern IntPtr GetWindow(IntPtr hWnd, GetWindowCmd uCmd);
}

第2步:定义窗口关系枚举

为GetWindow的参数提供清晰的枚举值,这里我们主要关注获取子窗口和下一个兄弟窗口。

public enum GetWindowCmd : uint
{
    GW_HWNDFIRST = 0,
    GW_HWNDLAST = 1,
    GW_HWNDNEXT = 2,
    GW_HWNDPREV = 3,
    GW_OWNER = 4,
    GW_CHILD = 5,  // 关键:获取第一个子窗口
    GW_ENABLEDPOPUP = 6
}

第3步:编写遍历逻辑

以下代码展示了如何在按钮点击事件中,从桌面窗口开始,递归或循环地捕获所有顶级子窗口。为了直观展示结果,代码将数据填入DataGridView控件中。

  1. 调用GetDesktopWindow()获取桌面句柄。
  2. 调用GetWindow(desktopPtr, GetWindowCmd.GW_CHILD)获取桌面的第一个子窗口(通常是第一层顶级窗口)。
  3. 在while循环中处理当前窗口,并利用GetWindow(currentPtr, GetWindowCmd.GW_HWNDNEXT)移动到下一个同级窗口,直到句柄为IntPtr.Zero。
// 假设 dataGridView1 已存在于界面上
private void button1_Click(object sender, EventArgs e)
{
    dataGridView1.Rows.Clear();
    
    // 1. 获取桌面窗口句柄
    IntPtr desktopPtr = GetDesktopWindow();
    
    // 2. 获取桌面下的第一个子窗口(顶层窗口)
    IntPtr winPtr = GetWindow(desktopPtr, GetWindowCmd.GW_CHILD);
    
    // 3. 循环遍历所有顶层子窗口
    while (winPtr != IntPtr.Zero)
    {
        try
        {
            // 此处可以添加逻辑:如获取窗口标题(GetWindowText)、关闭句柄等
            // string title = GetWindowText(winPtr); 
            
            // 示例:将句柄添加到表格
            dataGridView1.Rows.Add(new object[] { winPtr.ToInt32() });
            
            // 4. 获取下一个兄弟窗口
            winPtr = GetWindow(winPtr, GetWindowCmd.GW_HWNDNEXT);
        }
        catch (Exception ex)
        {
            Console.WriteLine($"Error processing window: {ex.Message}");
            break; 
        }
    }
}

运行效果与注意事项

执行上述代码后,程序会列出当前桌面上所有的顶层应用程序窗口句柄。

调试提示:

  • 空句柄检查:始终确保返回值不为IntPtr.Zero再继续操作,否则可能引发异常。
  • 窗口消失:如果某个窗口在遍历过程中被关闭或最小化,其句柄可能变为无效,建议包裹在try-catch中以保证程序健壮性。
  • 权限问题:以管理员身份运行时,部分系统保护窗口可能被跳过或无法完全读取属性。

以上就是基于GetDesktopWindow获得桌面所有窗口句柄的详细内容,更多关于C# Windows API编程的资料请关注本站其它相关文章!

相关标签:

本站声明

本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。

Python 相关产品和应用

全部下载

专题列表