C#实现操作Windows窗口句柄:常用窗口句柄相关API、Winform中句柄属性和Process的MainWindowHandle问题【窗口句柄总结之三】

简介: 本篇主要介绍一些与窗口句柄相关的一些API,比如设置窗口状态、当前激活的窗口、窗口客户区的大小、鼠标位置、禁用控件等,以及介绍Winform中的句柄属性,便于直接获取控件或窗体句柄,以及不推荐...

本篇主要介绍一些与窗口句柄相关的一些API,比如设置窗口状态、当前激活的窗口、窗口客户区的大小、鼠标位置、禁用控件等,以及介绍Winform中的句柄属性,便于直接获取控件或窗体句柄,以及不推荐使用C#自带的ProcessMainWindowHandle获取句柄的原因...

HWND窗口句柄其他的一些API

ShowWindow操作窗口状态(最大化、最小化、正常大小、关闭窗口)

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern bool ShowWindow(IntPtr hwnd, int nCmdShow);

nCmdShow参数表示窗体状态,其常见的取值含义为:

  • 0 —— SW_HIDE 隐藏窗口,并激活其他窗口
  • 1 —— SW_SHOWNORMAL/SW_NORMAL 激活并正常大小显示窗口
  • 2 —— SW_SHOWMINIMIZED 最小化窗口
  • 3 —— SW_SHOWMAXIMIZED/SW_MAXIMIZE 最大化窗口
  • 4 —— SW_SHOWNOACTIVATE 显示但不激活

更多的其它取值请查看官方文档中的介绍。

获取当前激活的正在工作的窗口句柄(获取当前活动窗口句柄)

返回值有可能为null

[DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
public static extern IntPtr GetForegroundWindow();

判断窗口状态

/// <summary>
/// 当前窗口是否最小化
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
/// <summary>
/// 当前窗口是否最大化
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32.dll")]
public static extern bool IsZoomed(IntPtr hWnd);
/// <summary>
/// 判断窗口是否可见
/// </summary>
/// <param name="hWnd"></param>
/// <returns></returns>
[DllImport("user32")]
public static extern bool IsWindowVisible(IntPtr hWnd);

设置窗口标题Title

[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int SetWindowText(IntPtr hWnd, string title);

获取窗口客户区大小

[DllImport("user32.dll")]
private static extern bool GetClientRect(IntPtr hwnd, out LPRECT lpRect);
/// <summary>
/// 获取窗口客户区大小
/// </summary>
/// <param name="hwnd"></param>
/// <returns></returns>
public static Rectangle GetClientRect(IntPtr hwnd)
{
    LPRECT rect = default;
    GetClientRect(hwnd, out rect);
    return new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
}

获取鼠标坐标

/// <summary>
/// 获取鼠标坐标
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
[DllImport("user32.dll", EntryPoint = "GetCursorPos")]
public static extern bool GetCursorPos(out Point pt);

获取指定坐标位置的窗体

/// <summary>
/// 获取指定位置所在的窗口句柄
/// </summary>
/// <param name="pt"></param>
/// <returns></returns>
[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]
public static extern IntPtr WindowFromPoint(Point pt);

获取鼠标指向的窗体

/// <summary>
/// 获取鼠标位置的窗体
/// </summary>
/// <returns></returns>
public static IntPtr WindowFromCursor()
{
    if (GetCursorPos(out Point pt))
    {
        return WindowFromPoint(pt);
    }
    return IntPtr.Zero;
}

移动或调整窗体大小

/// <summary>
/// 移动窗体、调整窗体大小
/// </summary>
/// <param name="hWnd"></param>
/// <param name="X">新位置</param>
/// <param name="Y">新位置</param>
/// <param name="nWidth">新大小</param>
/// <param name="nHeight">新大小</param>
/// <param name="bRepaint">是否重新渲染客户区,推荐始终为true</param>
/// <returns></returns>
[DllImport("user32.dll", SetLastError = true)]
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint=true);

使变灰的禁用控件可用

[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

Winform中使用窗口句柄

Handle属性

窗体或控件的Handle属性,可以直接获取对应的窗口句柄。

var frmHwnd = this.Handle;

var btnHwnd = button1.Handle;

获取某控件在Windows中的类名

Win 32 API 中窗口句柄的操作,很多有窗口或控件句柄的类名 ClassName这一项,比如 GetClassName API用于获取句柄的类名。

窗口(控件)句柄的类名是Windows系统中的类名,并不是winform/WPF内部C#的控件或元素类名,这一点要注意。

下面以一个Button按钮为例,通过属性button1.Handle句柄,获取其对应的类名GetClassName

[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetClassName(IntPtr hwnd, StringBuilder lpClassName, int nMaxCount);

private void button1_Click(object sender, EventArgs e)
{
    int nret;
    var className = new StringBuilder(255);
    nret = GetClassName(button1.Handle, className, className.Capacity);
    if (nret != 0)
        MessageBox.Show("ClassName is " + className.ToString());
    else
        MessageBox.Show("Error getting window class name");
}

获取Winform中Button控件的C#类名对应的window class name(GetClassName):WindowsForms10.BUTTON.app.0.xxx

通过Process进程类获取窗口句柄及相关信息【不推荐】

进程的MainWindowHandleMainWindowTitle

进程的MainWindowHandle属性可以直接获取主窗口句柄;MainWindowTitle属性为窗口的标题。

如下,根据窗口标题模糊查找窗口句柄。

/// <summary>
/// 根据窗口标题查找窗口句柄【不推荐】
/// </summary>
/// <param name="puzze_title">窗口标题,支持模糊查询可指定标题的一部分;为null则返回所有句柄</param>
/// <returns></returns>
public List<IntPtr> FindHwndsByTitle(string puzze_title=null)
{
    //按照窗口标题来寻找窗口句柄
    Process[] ps = Process.GetProcesses();
    var intptrs = new List<IntPtr>();
    foreach (Process p in ps)
    {
        if (puzze_title != null && !p.MainWindowTitle.Contains(puzze_title))
        {
            continue;
        }
        intptrs.Add(p.MainWindowHandle);
    }
    return intptrs;
}

MainWindow的问题

Process.MainWindowHandle属性是合成的(synthetic),Windows中并没有main window相关的正式概念;

一个程序可以创建多个可见的顶层窗口,对于Windows而言,它们都是相同的。

因此,推荐使用EnumWindows获取(顶层)窗口,即之前介绍到的FindAllWindows方法。

参考

相关文章
|
8月前
|
Ubuntu API C++
C++标准库、Windows API及Ubuntu API的综合应用
总之,C++标准库、Windows API和Ubuntu API的综合应用是一项挑战性较大的任务,需要开发者具备跨平台编程的深入知识和丰富经验。通过合理的架构设计和有效的工具选择,可以在不同的操作系统平台上高效地开发和部署应用程序。
320 11
|
设计模式 开发框架 安全
C# 一分钟浅谈:GraphQL API 与 C#
本文介绍了 GraphQL API 的基本概念及其优势,并通过 C# 实现了一个简单的 GraphQL 服务。GraphQL 是一种高效的 API 查询语言,允许客户端精确请求所需数据,减少不必要的数据传输。文章详细讲解了如何使用 `GraphQL.NET` 库在 C# 中创建和配置 GraphQL 服务,并提供了常见问题的解决方案和代码示例。
461 4
|
开发框架 .NET API
RESTful API 设计与实现:C# 开发者的一分钟入门
【10月更文挑战第5天】本文从零开始,介绍了如何使用 C# 和 ASP.NET Core 设计并实现一个简单的 RESTful API。首先解释了 RESTful API 的概念及其核心原则,然后详细说明了设计 RESTful API 的关键步骤,包括资源识别、URI 设计、HTTP 方法选择、状态码使用和错误处理。最后,通过一个用户管理 API 的示例,演示了如何创建项目、定义模型、实现控制器及运行测试,帮助读者掌握 RESTful API 的开发技巧。
917 7
|
人工智能 测试技术 API
Windows用户必备:Postman v11详细安装指南与API测试入门教程(附官网下载
Postman是全球领先的API开发与测试工具,支持REST、SOAP、GraphQL等协议调试。2025年最新版v11新增AI智能生成测试用例、多环境变量同步等功能,适用于前后端分离开发、自动化测试、接口文档自动生成及团队协作共享API资源。本文详细介绍Postman的软件定位、核心功能、安装步骤、首次配置、基础使用及常见问题解答,帮助用户快速上手并高效利用该工具进行API开发与测试。
|
存储 安全 编译器
学懂C#编程:属性(Property)的概念定义及使用详解
通过深入理解和使用C#的属性,可以编写更清晰、简洁和高效的代码,为开发高质量的应用程序奠定基础。
1501 12
|
安全 C# 索引
C#一分钟浅谈:属性与索引器的定义
本文深入浅出地介绍了C#编程中的属性和索引器。属性让字段更安全,通过访问器方法在读写时执行额外操作,如验证数据有效性;索引器则赋予类数组般的访问方式,支持基于索引的数据访问模式。文章通过示例代码展示了如何定义及使用这两种特性,并提供了常见问题及其解决方案,帮助读者写出更健壮、易维护的代码。希望读者能从中学习到如何有效利用属性和索引器增强C#类的功能性。
422 12
|
API C#
异步轮询 Web API 的实现与 C# 示例
异步轮询 Web API 的实现与 C# 示例
536 1
|
网络协议 API Windows
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
MASM32编程调用 API函数RtlIpv6AddressToString,windows 10 容易,Windows 7 折腾
|
存储 安全 编译器
C#中的属性
C#中的属性
219 7
|
开发框架 人工智能 自然语言处理
基于ChatGPT的API的C#接入研究
基于ChatGPT的API的C#接入研究