本篇主要介绍一些与窗口句柄相关的一些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();
判断窗口状态
///
/// 当前窗口是否最小化
///
///
///
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool IsIconic(IntPtr hWnd);
///
/// 当前窗口是否最大化
///
///
///
[DllImport("user32.dll")]
public static extern bool IsZoomed(IntPtr hWnd);
///
/// 判断窗口是否可见
///
///
///
[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);
///
/// 获取窗口客户区大小
///
///
///
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);
}
获取鼠标坐标
///
/// 获取鼠标坐标
///
///
///
[DllImport("user32.dll", EntryPoint = "GetCursorPos")]
public static extern bool GetCursorPos(out Point pt);
获取指定坐标位置的窗体
///
/// 获取指定位置所在的窗口句柄
///
///
///
[DllImport("user32.dll", EntryPoint = "WindowFromPoint")]
public static extern IntPtr WindowFromPoint(Point pt);
获取鼠标指向的窗体
///
/// 获取鼠标位置的窗体
///
///
public static IntPtr WindowFromCursor()
{
if (GetCursorPos(out Point pt))
{
return WindowFromPoint(pt);
}
return IntPtr.Zero;
}
移动或调整窗体大小
///
/// 移动窗体、调整窗体大小
///
///
/// 新位置
/// 新位置
/// 新大小
/// 新大小
/// 是否重新渲染客户区,推荐始终为true
///
[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属性为窗口的标题。
如下,根据窗口标题模糊查找窗口句柄。
///
/// 根据窗口标题查找窗口句柄【不推荐】
///
/// 窗口标题,支持模糊查询可指定标题的一部分;为null则返回所有句柄
///
public List
{
//按照窗口标题来寻找窗口句柄
Process[] ps = Process.GetProcesses();
var intptrs = new List
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方法。
参考
C#操作实例总结(二)—— 窗口操作
Why can’t FindWindowEx find another program’s window by name?
Working with Win32 API in .NET
https://www.pinvoke.net/index.aspx