用Graphics.CopyFromScreen截全屏需遍历Screen.AllScreens计算总边界,启用高DPI感知避免模糊,后台运行需UI权限或前台切换,保存时注意格式质量与资源释放。

直接用 Graphics.CopyFromScreen 就能截当前桌面,但默认只截主屏;多屏、DPI缩放、窗口遮挡、后台进程权限这几个地方最容易出错。
怎么用 Graphics.CopyFromScreen 截全屏(含多显示器)
系统可能有多个显示器,Graphics.CopyFromScreen 默认只从 (0, 0) 开始截,这在多屏环境下会漏掉副屏内容。得先遍历所有屏幕,算出总边界:
- 用
Screen.AllScreens获取所有显示器信息,调用Union合并所有Bounds得到完整矩形 - 创建对应尺寸的
Bitmap,再用Graphics.CopyFromScreen一次性复制整个区域 - 注意:不要用
Screen.PrimaryScreen.Bounds,它只返回主屏范围
示例关键片段:
var bounds = Screen.AllScreens.Aggregate((a, b) => Rectangle.Union(a.Bounds, b.Bounds)); using var bitmap = new Bitmap(bounds.Width, bounds.Height); using var g = Graphics.FromImage(bitmap); g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
为什么截图模糊或位置偏移?DPI 缩放是元凶
Windows 设置了「缩放与布局」(比如 125%、150%),会导致 Screen.Bounds 返回的是逻辑像素,而 CopyFromScreen 操作的是物理像素——不校正就必出错。
- 必须用
Graphics.DpiX/DpiY获取当前屏幕 DPI,再结合GetDpiForWindow(需 P/Invoke)判断是否启用高 DPI 感知 - 更稳妥的做法:在项目属性里勾选「启用高 DPI 感知」,并在
app.manifest中设置dpiAware="true"或"perMonitorV2" - 否则即使坐标算对了,截图也会被 Windows 自动缩放插值,导致模糊或边缘错位
后台运行时截图失败?权限和窗口状态决定成败
如果程序没有前台焦点(比如作为服务、定时任务、最小化后运行),CopyFromScreen 可能返回黑图或抛 ArgumentException。
- 这不是代码 bug,而是 Windows 图形子系统限制:GDI 截图依赖当前会话的桌面对象(WinStation),后台会话无法访问交互式桌面
- 解决方案只有两个:
Windows.Graphics.Capture(Win10 1809+,需 UI 权限且用户首次授权)或切换到前台再截图(不推荐,干扰用户) - 若必须无感知后台截图,考虑用
DesktopDuplication API(DirectX),但需要管理员权限 + 更复杂生命周期管理 - 测试时务必在「无焦点」「锁屏后唤醒」「远程桌面连接中」等场景验证
保存为 PNG/JPEG 时要注意什么
保存本身简单,但几个细节影响可用性:
- 用
bitmap.Save(path, ImageFormat.Png)保留透明通道(虽然桌面没透明,但后续叠加处理可能需要) - 若存 JPEG,避免用默认质量(
Encoder.Quality默认 75L),低质量压缩会导致文字边缘出现明显色块,建议设为 95L 以上 - 路径权限要检查:
Environment.GetFolderPath(Environment.SpecialFolder.Desktop)比硬写C:\Users\...更可靠 - 别忘了
Dispose()所有Graphics和Bitmap,否则长时间运行容易内存泄漏
截图功能看似一行 API 调用,但实际落地时,多屏坐标、DPI 感知、会话权限、保存质量这四点,任何一个疏忽都会让截图在真实环境中失效。


















