如何基于窗口句柄录制指定窗口?C#录屏程序改造需求
可以通过窗口句柄实现仅录制目标窗口
完全可以通过窗口句柄实现指定窗口的录制,核心思路是通过窗口句柄获取目标窗口的位置和尺寸,然后只捕获该区域的画面,以下是具体实现方案:
一、添加必要的Windows API调用
首先在NativeMethods类中补充获取窗口信息和捕获窗口画面的API:
public static class NativeMethods { [DllImport("winmm.dll", EntryPoint = "mciSendStringA", ExactSpelling = true, CharSet = CharSet.Ansi, SetLastError = true)] public static extern int record(string lpstrCommand, string lpstrReturnString, int uReturnLength, int hwndCallback); // 获取窗口的位置和尺寸 [DllImport("user32.dll")] public static extern bool GetWindowRect(IntPtr hWnd, out Rectangle lpRect); // 直接捕获窗口画面(即使窗口被遮挡也能捕获) [DllImport("user32.dll")] public static extern bool PrintWindow(IntPtr hWnd, IntPtr hdcBlt, uint nFlags); // 获取当前激活窗口句柄 [DllImport("user32.dll")] public static extern IntPtr GetForegroundWindow(); }
二、获取目标窗口的句柄和区域
你可以通过两种方式获取目标窗口句柄:
- 方式1:直接获取当前激活的窗口
IntPtr targetWindowHandle = NativeMethods.GetForegroundWindow(); Rectangle windowRect; NativeMethods.GetWindowRect(targetWindowHandle, out windowRect); - 方式2:实现窗口选择器,枚举所有窗口让用户手动选择(可结合
EnumWindowsAPI扩展)
拿到windowRect后,将其传入你的ScreenRecorder构造函数,替换原来的全屏bounds即可。
三、修改截图逻辑,精准捕获目标窗口
原来的CopyFromScreen会捕获屏幕指定区域,但如果窗口被遮挡会捕获到遮挡内容。更可靠的方式是用PrintWindow直接捕获窗口自身的画面:
public void RecordVideo(IntPtr targetWindowHandle) { watch.Start(); Rectangle windowRect; NativeMethods.GetWindowRect(targetWindowHandle, out windowRect); using (Bitmap bitmap = new Bitmap(windowRect.Width, windowRect.Height)) { using (Graphics g = Graphics.FromImage(bitmap)) { IntPtr hdc = g.GetHdc(); // 捕获整个窗口(包含边框和标题栏) NativeMethods.PrintWindow(targetWindowHandle, hdc, 0); g.ReleaseHdc(hdc); } string name = tempPath + "//screenshot-" + fileCount + ".png"; bitmap.Save(name, ImageFormat.Png); inputImageSequence.Add(name); fileCount++; } }
如果只需要捕获窗口的客户区(去掉标题栏和边框),可以补充以下API并调整逻辑:
[DllImport("user32.dll")] public static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect); [DllImport("user32.dll")] public static extern bool ClientToScreen(IntPtr hWnd, ref Point lpPoint); // 获取客户区屏幕区域示例 Rectangle clientRect; NativeMethods.GetClientRect(targetWindowHandle, out clientRect); Point topLeft = new Point(clientRect.Left, clientRect.Top); NativeMethods.ClientToScreen(targetWindowHandle, ref topLeft); Rectangle clientScreenRect = new Rectangle(topLeft, clientRect.Size);
四、处理窗口状态变化
如果目标窗口被移动、缩放,需要定时更新窗口区域,比如在录制循环中每隔一段时间重新获取windowRect,保证录制区域始终匹配窗口的最新位置。
五、适配现有代码的核心修改点
- 调整
ScreenRecorder构造函数,可接收窗口句柄参数,或在外部获取窗口Rect后传入原构造函数 - 替换
RecordVideo方法的全屏截图逻辑为窗口专属截图逻辑 - 在UI上添加"选择窗口"按钮,触发窗口选择逻辑并保存目标窗口句柄
内容的提问来源于stack exchange,提问作者SacredTravis
相关产品推荐
相关产品推荐

