using System;
using System.Collections.Generic;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Text;
namespace Walterlv.WindowDetector
{
///
/// 包含枚举当前用户空间下所有窗口的方法。
///
public class WindowEnumerator
{
///
/// 查找当前用户空间下所有符合条件的窗口。如果不指定条件,将仅查找可见窗口。
///
/// 过滤窗口的条件。如果设置为 null,将仅查找可见窗口。
/// 找到的所有窗口信息。
public static IReadOnlyList FindAll(Predicate match = null)
{
var windowList = new List();
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;
}
}
///
/// 显示窗口最前面
///
///
///
public static void ForceWindowIntoForeground(IntPtr window)
{
int currentThread = GetCurrentThreadId();
int activeWindow = GetForegroundWindow();
int activeThread = GetWindowThreadProcessId((IntPtr)activeWindow, out int activeProcess);
int windowThread = GetWindowThreadProcessId(window, out int windowProcess);
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, true);
if (windowThread != currentThread)
AttachThreadInput(windowThread, currentThread, true);
int oldTimeout = 0, newTimeout = 0;
SystemParametersInfo(0x2000, 0, ref oldTimeout, 0);
SystemParametersInfo(0x2000, 0, ref newTimeout, 0);
LockSetForegroundWindow(2);
AllowSetForegroundWindow(-1);
SetForegroundWindow(window);
ShowWindow(window, 9);
SystemParametersInfo(0x2000, 0, ref oldTimeout, 0);
if (currentThread != activeThread)
AttachThreadInput(currentThread, activeThread, false);
if (windowThread != currentThread)
AttachThreadInput(windowThread, currentThread, false);
}
///
/// 默认的查找窗口的过滤条件。可见 + 非最小化 + 包含窗口标题。
///
private static readonly Predicate DefaultPredicate = x => x.IsVisible && 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);
[DllImport("user32 ")]
public static extern long SetWindowPos(IntPtr hwnd, long hWndInsertAfter, long X, long y, long cx, long cy, long wFlagslong);
[DllImport("user32.dll")]
internal static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("User32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("User32.dll")]
private static extern bool ShowWindowAsync(IntPtr hWnd, int cmdShow);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, int hWndlnsertAfter, int X, int Y, int cx, int cy, uint Flags);
[DllImport("user32.dll", EntryPoint = "SystemParametersInfo")]
public static extern int SystemParametersInfo(int uAction, int uParam, IntPtr lpvParam, int fuWinIni);
[DllImport("User32.dll", SetLastError = true)]
public static extern int GetForegroundWindow();
[DllImport("User32.dll", CharSet = CharSet.Auto)]
public static extern int GetWindowThreadProcessId(IntPtr hwnd, out int ID);
[DllImport("User32.dll", SetLastError = true)]
private static extern int AttachThreadInput(int CurrentForegroundThread, int MakeThisThreadForegrouond, bool boolAttach);
[DllImport("kernel32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
public static extern int GetCurrentThreadId();
[DllImport("user32", CharSet = CharSet.Auto)]
static extern bool SystemParametersInfo(int uiAction, int uiParam, ref int pvParam, int fWinIni);
[DllImport("user32", CharSet = CharSet.Auto)]
static extern bool LockSetForegroundWindow(int a);
[DllImport("user32", CharSet = CharSet.Auto)]
static extern bool AllowSetForegroundWindow(int a);
[StructLayout(LayoutKind.Sequential)]
private readonly struct LPRECT
{
public readonly int Left;
public readonly int Top;
public readonly int Right;
public readonly int Bottom;
}
}
///
/// 获取 Win32 窗口的一些基本信息。
///
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;
}
///
/// 获取窗口句柄。
///
public IntPtr Hwnd { get; }
///
/// 获取窗口类名。
///
public string ClassName { get; }
///
/// 获取窗口标题。
///
public string Title { get; }
///
/// 获取当前窗口是否可见。
///
public bool IsVisible { get; }
///
/// 获取窗口当前的位置和尺寸。
///
public Rectangle Bounds { get; }
///
/// 获取窗口当前是否是最小化的。
///
public bool IsMinimized => Bounds.Left == -32000 && Bounds.Top == -32000;
}
}