本篇主要介绍一些与窗口句柄相关的一些API,比如设置窗口状态、当前激活的窗口、窗口客户区的大小、鼠标位置、禁用控件等,以及介绍Winform中的句柄属性,便于直接获取控件或窗体句柄,以及不推荐使用C#自带的Process
的MainWindowHandle
获取句柄的原因...
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进程类获取窗口句柄及相关信息【不推荐】
进程的MainWindowHandle
和MainWindowTitle
进程的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
方法。