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; } }