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

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

本篇主要介绍一些与窗口句柄相关的一些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 FindHwndsByTitle(string puzze_title=null)

{

//按照窗口标题来寻找窗口句柄

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

相关养生推荐

神兽 (恶搞)
体育365真正官网下载

神兽 (恶搞)

📅 08-10 👁️ 2715
定义何为成功的销售经理 - 从销售专员到销售经理:如何做好角色转换视频教程
为什么兔子的眼睛是红的,背后隐藏着怎样的生物学秘密呢?