如何将两个打开的窗口分置于左右两侧(类似Win+←/→效果)
实现窗口分屏到屏幕左右两侧
要实现打开窗口后自动分屏到左右(类似Win+←/→的效果),需要完成以下核心步骤:
- 打开目标窗口后,等待窗口创建并获取其句柄
- 获取屏幕工作区尺寸(排除任务栏等系统元素)
- 调用Windows API将窗口定位到左/右半屏区域
以下是修改后的完整代码:
using System; using System.Runtime.InteropServices; using System.Threading; namespace OpenWindows { class Program { // 导入所需Windows API [DllImport("Shell32.dll", CharSet = CharSet.Auto, SetLastError = true)] static extern IntPtr ShellExecute(IntPtr hwnd, string lpOperation, string lpFile, string lpParameters, string lpDirectory, int nShowCmd); [DllImport("user32.dll", SetLastError = true)] static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags); [DllImport("user32.dll")] static extern IntPtr MonitorFromWindow(IntPtr hwnd, uint dwFlags); [DllImport("user32.dll")] static extern bool GetMonitorInfo(IntPtr hMonitor, ref MONITORINFO lpmi); // 辅助结构体 [StructLayout(LayoutKind.Sequential)] public struct RECT { public int Left; public int Top; public int Right; public int Bottom; } [StructLayout(LayoutKind.Sequential)] public struct MONITORINFO { public int cbSize; public RECT rcMonitor; public RECT rcWork; public uint dwFlags; } // 循环等待窗口创建并获取句柄(最多等待10秒) static IntPtr WaitForWindow(string windowTitle, int timeoutSeconds = 10) { IntPtr hwnd = IntPtr.Zero; int attempts = timeoutSeconds * 10; while (attempts > 0) { hwnd = FindWindow(null, windowTitle); if (hwnd != IntPtr.Zero) break; Thread.Sleep(100); attempts--; } return hwnd; } // 将窗口定位到左半屏 static void MoveWindowToLeftHalf(IntPtr hwnd) { var monitorInfo = GetMonitorWorkArea(hwnd); int screenWidth = monitorInfo.rcWork.Right - monitorInfo.rcWork.Left; int screenHeight = monitorInfo.rcWork.Bottom - monitorInfo.rcWork.Top; SetWindowPos(hwnd, IntPtr.Zero, monitorInfo.rcWork.Left, monitorInfo.rcWork.Top, screenWidth / 2, screenHeight, 0x0040 | 0x0001); // SWP_SHOWWINDOW | SWP_NOZORDER } // 将窗口定位到右半屏 static void MoveWindowToRightHalf(IntPtr hwnd) { var monitorInfo = GetMonitorWorkArea(hwnd); int screenWidth = monitorInfo.rcWork.Right - monitorInfo.rcWork.Left; int screenHeight = monitorInfo.rcWork.Bottom - monitorInfo.rcWork.Top; SetWindowPos(hwnd, IntPtr.Zero, monitorInfo.rcWork.Left + screenWidth / 2, monitorInfo.rcWork.Top, screenWidth / 2, screenHeight, 0x0040 | 0x0001); // SWP_SHOWWINDOW | SWP_NOZORDER } // 获取窗口所在显示器的工作区信息(排除任务栏) static MONITORINFO GetMonitorWorkArea(IntPtr hwnd) { IntPtr monitor = MonitorFromWindow(hwnd, 0x00000002); // MONITOR_DEFAULTTONEAREST MONITORINFO monitorInfo = new MONITORINFO(); monitorInfo.cbSize = Marshal.SizeOf(monitorInfo); GetMonitorInfo(monitor, ref monitorInfo); return monitorInfo; } static void Main(string[] args) { // 打开存储设置窗口 ShellExecute(IntPtr.Zero, "open", "ms-settings:storagesense", "", null, 9); // 等待窗口加载并获取句柄(中文系统标题为"存储感知",其他语言需对应修改) IntPtr settingsHwnd = WaitForWindow("存储感知"); if (settingsHwnd != IntPtr.Zero) MoveWindowToLeftHalf(settingsHwnd); // 打开Edge浏览器窗口 ShellExecute(IntPtr.Zero, "open", "msedge.exe", "www.google.com", null, 9); // 等待窗口加载并获取句柄(中文系统标题为"Google - Microsoft Edge",其他语言需对应修改) IntPtr edgeHwnd = WaitForWindow("Google - Microsoft Edge"); if (edgeHwnd != IntPtr.Zero) MoveWindowToRightHalf(edgeHwnd); } } }
关键注意点:
- 窗口标题匹配:
WaitForWindow中的窗口标题需和当前系统语言对应,比如英文系统下存储设置窗口标题是"Storage Sense",Edge窗口标题是"Google - Microsoft Edge"。 - 等待机制:添加
Thread.Sleep循环等待窗口创建,避免因窗口未加载完成导致无法获取句柄。 - 工作区适配:通过
GetMonitorWorkArea获取显示器实际可用区域,确保窗口不会被任务栏遮挡。
内容的提问来源于stack exchange,提问作者afei
相关产品推荐
相关产品推荐

