取消

Win32/C# 应用使用 PrintWindow 对窗口截图(PrintWindow)

相比于 Windows 2000 引入到 GDI+ 中的 BitBlt 方法截取窗口图片,Windows XP 时也引入了 PrintWindow 方法来专门截取窗口,截取的原理也不同。

微软 Office 系列里的截取窗口,用的就是 PrintWindow 方法。


开始截图

相比于使用 BitBlt 方法,使用 PrintWindow 截取窗口的代码少得多。

你需要引用如下命名空间:

1
2
3
using System.Drawing;
using System.Drawing.Imaging;
using System.Drawing.Graphics;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public static byte[] CaptureWindow(HWND hWnd, int width, int height)
{
   using (var bmp = new Bitmap(width, height))
   {
       using (Graphics memoryGraphics = Graphics.FromImage(bmp))
       {
           IntPtr dc = memoryGraphics.GetHdc();
           PrintWindow(hWnd, dc, 0);
           memoryGraphics.ReleaseHdc(dc);

           using (MemoryStream ms = new MemoryStream())
           {
               bmp.Save(ms, ImageFormat.Png);
               ms.Seek(0, SeekOrigin.Begin);
               return ms.ToArray();
           }
       }
   }
}

[DllImport("User32.dll", SetLastError = true)]
static extern bool PrintWindow(IntPtr hwnd, IntPtr hdc, uint nFlags);

原理、效果和问题

使用 PrintWindow 来截图时,目标窗口会收到一次 WM_PRINTWM_PRINTCLIENT 消息以完成一次绘图。并且,此过程是同步进行的,如果目标窗口在处理消息时没有返回,那么这里的调用将一直挂起。

使用此方法截图时,DWM 绘制的窗口部分在真实窗口中和实际截出来的会不一样,是关掉了 Aero 效果时的窗口样式。

关掉了 Aero 样式的截图

当然,还有可能把目标窗口截挂:

截到没有目标窗口了

更多截窗口方法


参考资料

本文会经常更新,请阅读原文: https://blog.walterlv.com/post/win32-capture-window-using-print-window.html ,以避免陈旧错误知识的误导,同时有更好的阅读体验。

知识共享许可协议

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 吕毅 (包含链接: https://blog.walterlv.com ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。如有任何疑问,请 与我联系 ([email protected])

登录 GitHub 账号进行评论