共计 2882 个字符,预计需要花费 8 分钟才能阅读完成。
背景痛点
开发者在实现屏幕录制功能时,常常会遇到以下几个棘手的问题:

- 跨版本兼容性:不同版本的 Windows 系统对录屏 API 的支持程度不同,自行实现的方案往往需要在多个系统版本上测试和调整。
- 性能开销:录屏功能对 CPU 和内存的消耗较大,尤其是在高帧率和高分辨率的情况下,容易导致系统卡顿甚至崩溃。
- 权限问题:某些 API 需要管理员权限或特定的用户权限才能调用,增加了开发和部署的复杂性。
- 内存泄漏风险:频繁的截图和视频编码操作容易导致内存泄漏,尤其是在长时间录屏时。
技术选型
在 C# 中实现录屏功能,常见的技术方案有以下几种:
- DirectX:性能最优,但实现复杂,需要深入了解 DirectX API。
- Windows.Graphics.Capture:Windows 10 及以上版本支持,相对简单,但对系统版本有要求。
- 调用系统工具(如 Snipping Tool):兼容性好,实现简单,但功能相对有限。
对于大多数开发者来说,调用系统工具是一个快速上手的方案,尤其是在需要兼容旧版 Windows 系统时。
核心实现
1. 使用 P /Invoke 调用关键 API
通过 P /Invoke 调用 user32.dll 和gdi32.dll中的 API,可以实现屏幕截图功能。以下是关键 API 的调用示例:
[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
2. 截图采集与帧合成
截图采集的核心步骤如下:
- 获取屏幕的 DC(设备上下文)。
- 创建兼容的位图对象。
- 将屏幕内容拷贝到位图中。
- 保存位图为图像文件或进行进一步处理。
帧合成则是将多个截图按时间顺序合成为视频文件,可以使用 FFmpeg 等工具实现。
3. 视频编码
视频编码是将连续的截图帧转换为视频流的过程。常用的编码器有 H.264 和 H.265,可以通过 FFmpeg 或 Windows Media Foundation 实现。
代码示例
以下是一个完整的 C# 类封装,实现了屏幕截图和录屏功能:
using System;
using System.Drawing;
using System.Runtime.InteropServices;
public class ScreenRecorder
{[DllImport("user32.dll")]
public static extern IntPtr GetDesktopWindow();
[DllImport("user32.dll")]
public static extern IntPtr GetWindowDC(IntPtr hWnd);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleBitmap(IntPtr hdc, int nWidth, int nHeight);
[DllImport("gdi32.dll")]
public static extern IntPtr CreateCompatibleDC(IntPtr hdc);
[DllImport("gdi32.dll")]
public static extern bool BitBlt(IntPtr hdcDest, int nXDest, int nYDest, int nWidth, int nHeight, IntPtr hdcSrc, int nXSrc, int nYSrc, int dwRop);
[DllImport("gdi32.dll")]
public static extern IntPtr SelectObject(IntPtr hdc, IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern bool DeleteObject(IntPtr hObject);
[DllImport("gdi32.dll")]
public static extern bool DeleteDC(IntPtr hdc);
public static Bitmap CaptureScreen()
{IntPtr hdcSrc = GetWindowDC(GetDesktopWindow());
IntPtr hdcDest = CreateCompatibleDC(hdcSrc);
int width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
int height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;
IntPtr hBitmap = CreateCompatibleBitmap(hdcSrc, width, height);
IntPtr hOld = SelectObject(hdcDest, hBitmap);
BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, 0x00CC0020);
Bitmap bmp = Image.FromHbitmap(hBitmap);
SelectObject(hdcDest, hOld);
DeleteObject(hBitmap);
DeleteDC(hdcDest);
DeleteDC(hdcSrc);
return bmp;
}
}
生产环境考量
1. 多显示器适配
在多显示器环境下,需要获取所有显示器的分辨率信息,并根据需要选择录制的显示器。可以通过 System.Windows.Forms.Screen.AllScreens 获取所有显示器的信息。
2. 内存优化
频繁的截图和视频编码操作容易导致内存泄漏和 GC 压力。可以通过以下方式优化:
- 使用对象池管理 Bitmap 对象。
- 及时释放非托管资源(如 DC 和位图对象)。
- 限制帧率,避免不必要的资源消耗。
3. 防杀毒软件误报
某些杀毒软件可能会将录屏程序误报为恶意软件。可以通过以下方式减少误报:
- 使用代码签名证书对程序进行签名。
- 在程序中添加详细的说明文档和用户提示。
- 避免使用敏感 API 或行为。
避坑指南
- Windows 10/11 差异处理:某些 API 在 Windows 10 和 Windows 11 上的行为可能不同,需要进行兼容性测试。
- DPI 缩放问题:在高 DPI 显示器上,截图可能会出现缩放问题,需要通过
SetProcessDPIAwareAPI 解决。 - 权限问题:某些 API 需要管理员权限,可以在程序清单文件中声明
requireAdministrator。
开放性问题
如何扩展为支持 GPU 加速的解决方案?可以考虑使用 DirectX 或 Windows.Graphics.Capture API,结合 GPU 编码器(如 NVENC)来实现高性能录屏。
正文完
发表至: 编程开发
近两天内
