自制指定窗口录屏工具无法移动目标窗口的问题求助
问题描述
我开发了一款可录制用户选定指定窗口的录屏工具,但录制过程中程序会强制目标窗口始终处于激活状态,导致完全无法移动窗口或调整窗口大小,甚至无法停止录制。请问有什么解决办法?
原代码片段
下拉框选择事件代码
private void Handlebox_SelectedIndexChanged(object sender, EventArgs e) { if (Handlebox.SelectedIndex == -1) return; handle_name = Handlebox.SelectedItem.ToString(); }
向下拉框添加进程的代码
foreach (Process process in processlist) { if (!String.IsNullOrEmpty(process.MainWindowTitle)) { Handlebox.Items.Add(process.ProcessName); } }
录屏核心代码
// Record video: [StructLayout(LayoutKind.Sequential)] public struct Rect { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] private static extern int SetForegroundWindow(IntPtr hWnd); private const int SW_RESTORE = 9; [DllImport("user32.dll")] private static extern IntPtr ShowWindow(IntPtr hWnd, int nCmdShow); [DllImport("user32.dll")] public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect); public Bitmap CaptureApplication(string procName) { Process proc; // Cater for cases when the process can't be located. try { proc = Process.GetProcessesByName(procName)[0]; } catch (IndexOutOfRangeException e) { return null; } // You need to focus on the application SetForegroundWindow(proc.MainWindowHandle); ShowWindow(proc.MainWindowHandle, SW_RESTORE); // Delay Thread.Sleep(1000); Rect rect = new Rect(); IntPtr error = GetWindowRect(proc.MainWindowHandle, ref rect); // sometimes it gives error. while (error == (IntPtr)0) { error = GetWindowRect(proc.MainWindowHandle, ref rect); } int width = rect.right - rect.left; int height = rect.bottom - rect.top; Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); Graphics.FromImage(bmp).CopyFromScreen(rect.left,rect.top,0,0,new Size(width, height),CopyPixelOperation.SourceCopy); return bmp; } public void RecordVideo() { // Keep track of time: watch.Start(); // Save screenshot: string name = tempPath + "//screenshot-" + fileCount + ".png"; CaptureApplication(handle_name).Save(name, ImageFormat.Png); inputImageSequence.Add(name); fileCount++; // Dispose of bitmap: CaptureApplication(handle_name).Dispose(); }
解决办法及修改后的代码
问题根源在于每次截图都强制激活并恢复目标窗口,且录制时重复调用截图方法,导致窗口被反复抢占焦点。以下是针对性修改:
1. 改用窗口句柄定位目标窗口(避免同名进程冲突)
原代码用进程名查找窗口易出现多进程冲突,改为直接存储窗口句柄和标题:
修改下拉框填充代码:
// 先清空下拉框 Handlebox.Items.Clear(); foreach (Process process in Process.GetProcesses()) { if (!string.IsNullOrEmpty(process.MainWindowTitle)) { // 存储窗口句柄和标题,用Tuple示例 Handlebox.Items.Add(new Tuple<IntPtr, string>(process.MainWindowHandle, process.MainWindowTitle)); // 设置下拉框显示标题 Handlebox.DisplayMember = "Item2"; } }
修改下拉框选择事件:
private IntPtr targetWindowHandle; // 全局变量存储目标窗口句柄 private void Handlebox_SelectedIndexChanged(object sender, EventArgs e) { if (Handlebox.SelectedIndex == -1) { targetWindowHandle = IntPtr.Zero; return; } var selectedItem = (Tuple<IntPtr, string>)Handlebox.SelectedItem; targetWindowHandle = selectedItem.Item1; }
2. 移除强制激活窗口的代码,优化截图逻辑
不需要激活窗口也能获取其位置并截图,删除SetForegroundWindow和ShowWindow(SW_RESTORE),同时避免死循环重试:
修改截图核心方法:
[StructLayout(LayoutKind.Sequential)] public struct Rect { public int left; public int top; public int right; public int bottom; } [DllImport("user32.dll")] public static extern IntPtr GetWindowRect(IntPtr hWnd, ref Rect rect); public Bitmap CaptureWindow(IntPtr hWnd) { if (hWnd == IntPtr.Zero) return null; Rect rect = new Rect(); // 最多重试3次获取窗口位置,避免死循环 int retryCount = 0; IntPtr error = GetWindowRect(hWnd, ref rect); while (error == IntPtr.Zero && retryCount < 3) { Thread.Sleep(100); error = GetWindowRect(hWnd, ref rect); retryCount++; } if (error == IntPtr.Zero) return null; int width = rect.right - rect.left; int height = rect.bottom - rect.top; // 处理窗口最小化的情况 if (width <= 0 || height <= 0) return null; Bitmap bmp = new Bitmap(width, height, PixelFormat.Format32bppArgb); using (Graphics g = Graphics.FromImage(bmp)) { g.CopyFromScreen(rect.left, rect.top, 0, 0, new Size(width, height), CopyPixelOperation.SourceCopy); } return bmp; }
3. 优化录制逻辑,避免重复截图
原代码在RecordVideo中调用两次截图方法,改为调用一次并正确释放资源:
public void RecordVideo() { watch.Start(); string name = Path.Combine(tempPath, $"screenshot-{fileCount}.png"); using (Bitmap bmp = CaptureWindow(targetWindowHandle)) { if (bmp != null) { bmp.Save(name, ImageFormat.Png); inputImageSequence.Add(name); fileCount++; } } }
额外优化建议
- 录制过程用后台线程执行截图操作,避免阻塞UI线程,确保停止录制按钮可正常响应。
- 录制时实时检测窗口状态(如关闭、最小化),及时抛出提示或暂停录制。
内容的提问来源于stack exchange,提问作者SacredTravis
相关产品推荐
相关产品推荐

