graphics.copyfromscreen截多屏需遍历screen.allscreens计算虚拟桌面边界并传入bounds.location作为源坐标,保存png必须显式指定imageformat.png以防alpha丢失,远程桌面或锁屏时会因gdi权限限制失效。

直接用 Graphics.CopyFromScreen 能截,但默认只截主屏、不支持多显示器坐标偏移、保存时若没指定编码器会丢 Alpha 通道或报错——这是最常卡住的三个点。
怎么用 Graphics 截全屏(含多显示器)
关键不是“能不能截”,而是“截哪块”。Graphics.CopyFromScreen 的前四个参数是源矩形(x, y, width, height),必须自己算准。多屏环境下,不能硬写 (0, 0, Screen.PrimaryScreen.Bounds.Width, ...),得遍历 Screen.AllScreens 拼出虚拟桌面边界:
var bounds = Screen.AllScreens
.Aggregate(Rectangle.Empty, (r1, r2) => Rectangle.Union(r1, r2.Bounds));
using var bitmap = new Bitmap(bounds.Width, bounds.Height);
using var g = Graphics.FromImage(bitmap);
g.CopyFromScreen(bounds.Location, Point.Empty, bounds.Size);
-
bounds.Location是左上角在虚拟桌面坐标系里的偏移(比如副屏在主屏右边,x 就是正数) - 别用
Screen.PrimaryScreen.Bounds替代bounds,否则副屏内容直接被裁掉 - 如果只要当前活动窗口所在屏,用
Screen.FromControl(this).Bounds更稳
为什么截图保存成 PNG 却变黑/透明?
因为 Bitmap.Save 默认用 BMP 编码器,而 BMP 不支持带 Alpha 的 ARGB 像素格式。你创建的 Bitmap 内部是 PixelFormat.Format32bppArgb,但没显式指定编码器就存 PNG,.NET 会 fallback 到 BMP 并静默失败。
- 必须显式传
ImageCodecInfo.GetImageEncoders()找到 PNG 编码器 - 或者更简单:用
bitmap.Save(path, ImageFormat.Png)—— 这个重载内部会选对编码器 - 千万别写
bitmap.Save(path, ImageFormat.Bmp)然后改后缀名,BMP 文件头和像素布局跟 PNG 完全不同
Graphics.CopyFromScreen 在远程桌面/锁屏时失效怎么办?
这不是代码 bug,是 Windows GDI 权限限制:CopyFromScreen 依赖前台桌面会话的图形上下文,远程连接或系统锁屏后,会话被挂起,调用直接返回黑图或抛 ArgumentException。
- 真要后台截图,得换方案:用
Windows.Graphics.Capture(Win10 1809+)或Desktop Duplication API(C++/COM) - 临时绕过:加 try-catch,捕获
ArgumentException后降级为截当前窗口客户区(this.DrawToBitmap) - 服务进程里绝对不要调
CopyFromScreen,它根本没桌面会话
真正麻烦的从来不是“怎么调那个函数”,而是搞清你要截的是谁眼中的屏幕——用户当前看到的?远程桌面客户端渲染后的?还是锁屏界面背后的登录会话?选错上下文,代码再对也没用。











