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

2023-10-22 11:04:40 浏览数 (3)

相比于 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 效果时的窗口样式。

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

更多截窗口方法

  • Win32/C# 应用使用 GDI 对窗口截图(BitBlt) - walterlv
  • Win32/C# 应用不依赖任何库使用纯 GDI 对窗口截图(BitBlt) - walterlv
  • (本文)Win32/C# 应用使用 PrintWindow 对窗口截图(PrintWindow) - walterlv

参考资料

  • PrintWindow function (winuser.h) - Win32 apps - Microsoft Docs
  • office的截屏是用的什么技术? - 知乎

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

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

0 人点赞