原文:Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题、位置、尺寸、最小化、可见性等各种状态

在 Windows 应用开发中,如果需要操作其他的窗口,那么可以使用 EnumWindows 这个 API 来枚举这些窗口。

你可以使用本文编写的一个类型,查找到所有窗口中你关心的信息。


需要使用的 API

枚举所有窗口仅需要使用到 EnumWindows,其中需要定义一个委托 WndEnumProc 作为传入参数的类型。

剩下的我们需要其他各种方法用于获取窗口的其他属性。

private delegate bool WndEnumProc(IntPtr hWnd, int lParam);

[DllImport("user32")]
private static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam); [DllImport("user32")]
private static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32")]
private static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lptrString, int nMaxCount); [DllImport("user32")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32")]
private static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect); [StructLayout(LayoutKind.Sequential)]
private readonly struct LPRECT
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

枚举所有窗口

我将以上 API 封装成 FindAll 函数,并提供过滤器可以给大家过滤众多的窗口使用。

比如,我写了下面一个简单的示例,可以输出当前可见的所有窗口以及其位置和尺寸:

using System;

namespace Walterlv.WindowDetector
{
class Program
{
static void Main(string[] args)
{
var windows = WindowEnumerator.FindAll();
for (int i = 0; i < windows.Count; i++)
{
var window = windows[i];
Console.WriteLine($@"{i.ToString().PadLeft(3, ' ')}. {window.Title}
{window.Bounds.X}, {window.Bounds.Y}, {window.Bounds.Width}, {window.Bounds.Height}");
}
Console.ReadLine();
}
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

这里的 FindAll 方法,我提供了一个默认参数,可以指定如何过滤所有枚举到的窗口。如果不指定,则会找可见的,包含标题的,没有最小化的窗口。如果你希望找一些看不见的窗口,可以自己写过滤条件。

什么都不要过滤的话,就传入 _ => true,意味着所有的窗口都会被枚举出来。

附源码

因为源代码会经常更新,所以建议在这里查看:

无法访问的话,可以看下面:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text; namespace Walterlv.WindowDetector
{
/// <summary>
/// 包含枚举当前用户空间下所有窗口的方法。
/// </summary>
public class WindowEnumerator
{
/// <summary>
/// 查找当前用户空间下所有符合条件的窗口。如果不指定条件,将仅查找可见窗口。
/// </summary>
/// <param name="match">过滤窗口的条件。如果设置为 null,将仅查找可见窗口。</param>
/// <returns>找到的所有窗口信息。</returns>
public static IReadOnlyList<WindowInfo> FindAll(Predicate<WindowInfo> match = null)
{
var windowList = new List<WindowInfo>();
EnumWindows(OnWindowEnum, 0);
return windowList.FindAll(match ?? DefaultPredicate); bool OnWindowEnum(IntPtr hWnd, int lparam)
{
// 仅查找顶层窗口。
if (GetParent(hWnd) == IntPtr.Zero)
{
// 获取窗口类名。
var lpString = new StringBuilder(512);
GetClassName(hWnd, lpString, lpString.Capacity);
var className = lpString.ToString(); // 获取窗口标题。
var lptrString = new StringBuilder(512);
GetWindowText(hWnd, lptrString, lptrString.Capacity);
var title = lptrString.ToString().Trim(); // 获取窗口可见性。
var isVisible = IsWindowVisible(hWnd); // 获取窗口位置和尺寸。
LPRECT rect = default;
GetWindowRect(hWnd, ref rect);
var bounds = new Rectangle(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top); // 添加到已找到的窗口列表。
windowList.Add(new WindowInfo(hWnd, className, title, isVisible, bounds));
} return true;
}
} /// <summary>
/// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
/// </summary>
private static readonly Predicate<WindowInfo> DefaultPredicate = x => x.IsVisible && !x.IsMinimized && x.Title.Length > 0; private delegate bool WndEnumProc(IntPtr hWnd, int lParam); [DllImport("user32")]
private static extern bool EnumWindows(WndEnumProc lpEnumFunc, int lParam); [DllImport("user32")]
private static extern IntPtr GetParent(IntPtr hWnd); [DllImport("user32")]
private static extern bool IsWindowVisible(IntPtr hWnd); [DllImport("user32")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lptrString, int nMaxCount); [DllImport("user32")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpString, int nMaxCount); [DllImport("user32")]
private static extern void SwitchToThisWindow(IntPtr hWnd, bool fAltTab); [DllImport("user32")]
private static extern bool GetWindowRect(IntPtr hWnd, ref LPRECT rect); [StructLayout(LayoutKind.Sequential)]
private readonly struct LPRECT
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
} /// <summary>
/// 获取 Win32 窗口的一些基本信息。
/// </summary>
public readonly struct WindowInfo
{
public WindowInfo(IntPtr hWnd, string className, string title, bool isVisible, Rectangle bounds) : this()
{
Hwnd = hWnd;
ClassName = className;
Title = title;
IsVisible = isVisible;
Bounds = bounds;
} /// <summary>
/// 获取窗口句柄。
/// </summary>
public IntPtr Hwnd { get; } /// <summary>
/// 获取窗口类名。
/// </summary>
public string ClassName { get; } /// <summary>
/// 获取窗口标题。
/// </summary>
public string Title { get; } /// <summary>
/// 获取当前窗口是否可见。
/// </summary>
public bool IsVisible { get; } /// <summary>
/// 获取窗口当前的位置和尺寸。
/// </summary>
public Rectangle Bounds { get; } /// <summary>
/// 获取窗口当前是否是最小化的。
/// </summary>
public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138

我的博客会首发于 https://blog.walterlv.com/,而 CSDN 会从其中精选发布,但是一旦发布了就很少更新。

如果在博客看到有任何不懂的内容,欢迎交流。我搭建了 dotnet 职业技术学院 欢迎大家加入。

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。欢迎转载、使用、重新发布,但务必保留文章署名吕毅(包含链接:https://walterlv.blog.csdn.net/),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请与我联系

发布了382 篇原创文章 · 获赞 232 · 访问量 47万+

Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题、位置、尺寸、最小化、可见性等各种状态的更多相关文章

  1. windows系统上安装与使用Android NDK r5 (转)

    windows系统上安装与使用Android NDK r5  很早就听说了android的NDK应用,只是一直没有时间去研究,今天花了点时间在windows平台搭建了NDK环境,并成功运行了第一个简单 ...

  2. spm完成dmp在windows系统上导入详细过程

    --查询dmp字符集 cat spmprd_20151030.dmp ','xxxx')) from dual; spm完成dmp在windows系统上导入详细过程 create tablespace ...

  3. 快速获取Windows系统上的国家和地区信息

    Windows系统上包含了200多个国家和地区的数据,有时候编程需要这些资料.以下代码可以帮助你快速获取这些信息.将Console语句注释掉,可以更快的完成分析. static void Main(s ...

  4. Windows系统上如何使用SSH

    Windows系统上如何使用SSH 传统的网络服务程序如FTP.Telnet等,在网络上一般使用明文传送数据.用户账号和口令信息,容易受到中间人的攻击.用户利用SSH协议后能有效防止DNS及IP欺骗, ...

  5. 如何在Windows系统上用抓包软件Wireshark截获iPhone等网络通讯数据

    http://www.jb51.net/os/windows/189090.html 今天给大家介绍一种如何在Windows操作系统上使用著名的抓包工具软件Wireshark来截获iPhone.iPa ...

  6. Redis进阶实践之三如何在Windows系统上安装安装Redis

    一.Redis的简介        Redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合 ...

  7. 非Unicode编码的软件如何在Windows系统上运行

    我们常常会遇到这样一种情况:点开某些日文软件(我不会说就是galgame( ╯□╰ ))会出现乱码或者直接无法运行. 出现乱码的原因很简单:编码与译码的方式不一致!!!!!!!!!!! 首先大家需要知 ...

  8. 在windows系统上使用pip命令安装python的第三方库

    在windows系统上使用pip命令安装python的第三方库 通过cmd启动命令行后,直接输入pip命令,有时候命令行会提示我们pip不是一个指令,这个时候我们可以通过python的集成开发环境里面 ...

  9. 在Windows系统上一批可以下载但是需要经过编译再安装的第三方的直接编译后的版本(UCI页面)

    在Windows系统上一批可以下载但是需要经过编译再安装的第三方的直接编译后的版本(UCI页面) (https://www.lfd.uci.edu/~gohlke/pythonlibs/) win10 ...

随机推荐

  1. GoCN每日新闻(2019-10-07)

    GoCN每日新闻(2019-10-07) 国庆专辑:GopherChina 祝大家国庆节快乐(假期最后一天)   GoCN每日新闻(2019-10-07)   1. Go 不好的点:JSON 解析的探 ...

  2. PHP 打印输出数组内容及结构 print_r 与 var_dump 函数

    利用 print_r() 函数可以打印输出整个数组内容及结构,按照一定格式显示键和元素.注意 print_r() 函数不仅是只用于打印,实际它是用于打印关于变量的易于理解的信息. 例子1 <?p ...

  3. Beta冲刺(2/5)

    队名:無駄無駄 组长博客 作业博客 组员情况 张越洋 过去两天完成了哪些任务 数据库实践 提交记录(全组共用) 接下来的计划 加快校园百科的进度 还剩下哪些任务 学习软工的理论课 学习代码评估.测试 ...

  4. 【BIEE】报表导出数据只显示500行,如何解决?

    BIEE报表展示的时候每页只显示500行,进而导致导出的时候也只能导出500行,客户抱怨:每次只能导出500行,导出后还得自己合并! 解决思路: 1.找到路径$BIEE_HOME\instances\ ...

  5. D3.js的v5版本入门教程(第三章)—— 选择元素和绑定数据

    D3.js的v5版本入门教程(第三章) 在D3.js中,选择元素和绑定元素是最基本的内容,也是很重要的内容,等你看完整个教程后你会发现,这些D3.js教程都是在选择元素和绑定元素的基础上展开后续工作的 ...

  6. Hadoop综合大作业总评

    作业来源:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE1/homework/3363 1.把python爬取的数据传到linux 2.把数据的逗号代替为  ...

  7. 团队作业-Beta版本演示

    组长博客链接 https://www.cnblogs.com/cmlei/p/12063671.html 本组成员 031702431 陈明磊 组长 031702227 林镕炜 031702413 韩 ...

  8. F12修改html进行本地js操作页面元素

    F12修改html进行本地js操作页面元素

  9. 含有虚拟列的表 怎么用EXP导出?

    最近导一个测试库,报有虚拟列的表不支持,如下: EXP-00107: Feature (VIRTUAL COLUMN) of column CTB_CLIENT_SUBMIT_TIME_MONTH i ...

  10. git 只提交部分修改文件

    1.git status //查看修改文件状态 2.git add  //将想要提交的文件add到本地库 4.git status  //查看修改文件状态 3.git commit  //提交add到 ...