using anjianjingling.Native; using System.Diagnostics; using System.Text; namespace anjianjingling.Window { public record WindowInfo(IntPtr Handle, string Title); /// /// 系统级窗口管理:枚举、查找、激活、启动程序、后台消息投递。 /// public sealed class WindowManager { /// 启动外部程序或打开文件。 public void Launch(string path, string? arguments = null) { var psi = new ProcessStartInfo { FileName = path, UseShellExecute = true }; if (!string.IsNullOrWhiteSpace(arguments)) psi.Arguments = arguments; Process.Start(psi); } /// 枚举所有可见且有标题的顶层窗口。 public List GetWindows() { var list = new List(); Win32.EnumWindows((h, _) => { if (Win32.IsWindowVisible(h)) { int len = Win32.GetWindowTextLength(h); if (len > 0) { var sb = new StringBuilder(len + 1); Win32.GetWindowText(h, sb, sb.Capacity); var title = sb.ToString().Trim(); if (title.Length > 0) list.Add(new WindowInfo(h, title)); } } return true; }, IntPtr.Zero); return list; } /// 按标题关键字(包含匹配,不区分大小写)查找窗口。 public IntPtr FindByTitle(string keyword) { foreach (var w in GetWindows()) { if (w.Title.Contains(keyword, StringComparison.OrdinalIgnoreCase)) return w.Handle; } return IntPtr.Zero; } /// 激活窗口并前置(最小化则恢复,使用 AttachThreadInput 解决前台锁定)。 public bool Activate(IntPtr hWnd) { if (hWnd == IntPtr.Zero) return false; if (Win32.IsIconic(hWnd)) Win32.ShowWindow(hWnd, Win32.SW_RESTORE); uint foregroundThread = Win32.GetWindowThreadProcessId(Win32.GetForegroundWindow(), out _); uint currentThread = Win32.GetCurrentThreadId(); if (foregroundThread != currentThread) { Win32.AttachThreadInput(currentThread, foregroundThread, true); Win32.SetForegroundWindow(hWnd); Win32.AttachThreadInput(currentThread, foregroundThread, false); } else { Win32.SetForegroundWindow(hWnd); } return true; } /// 按标题激活。 public bool ActivateByTitle(string keyword) { var h = FindByTitle(keyword); return h != IntPtr.Zero && Activate(h); } /// 获取窗口屏幕矩形。 public Rectangle? GetBounds(IntPtr hWnd) { if (Win32.GetWindowRect(hWnd, out var r)) return new Rectangle(r.Left, r.Top, r.Width, r.Height); return null; } /// /// 后台点击:向窗口句柄 PostMessage 发送鼠标按下/弹起(客户区坐标),不抢焦点。 /// 注意:对 DirectX/自绘程序可能无效。 /// public void PostClick(IntPtr hWnd, int clientX, int clientY, bool right = false) { var lp = Win32.MakeLParam(clientX, clientY); uint down = right ? Win32.WM_RBUTTONDOWN : Win32.WM_LBUTTONDOWN; uint up = right ? Win32.WM_RBUTTONUP : Win32.WM_LBUTTONUP; Win32.PostMessage(hWnd, down, Win32.MK_LBUTTON, lp); Thread.Sleep(60); Win32.PostMessage(hWnd, up, IntPtr.Zero, lp); } } }