Windows桌面共享中一些常见的抓屏技术

摘要:
它有一个名为WindowsMediaVideo9Screencode的编码器,专门针对屏幕捕获进行了优化。Windows Media Encoder API提供了一个IWMEncoder2接口,可用于高效捕获屏幕图像。最后,在简要总结中,我们可以看到,在Windows系统上基本上没有通用的屏幕捕获技术可以有效地捕获所有系统,这主要是因为操作系统的显示驱动程序模型正在从XPDM变为WDDM,应用层的API也在从GDI变为D3D。
1. BitBlt

我想做Windows开发应该都知道这个API, 它能实现DC间的内容拷贝, 如果我们把源DC指定成Monitor DC或是桌面DC, 它就能实现抓屏功能。
对于通过这种方式的抓屏, 有2点需要特别提醒:
a. 在XP下我们可以通过最后的拷贝标志来控制是否拷贝layered window, 只有SRCCPY表示拷贝内容不包含layered window, 如果是SRCCPY | CAPTUREBLT表示拷贝包括Layered window在内的所有窗口。 这个标志在Vista之后的系统(win7/win8),开启DWM的情况下, 已经失效, 因为这种情况下所有的窗口都是layered window.
b. 这种方式的抓屏在 Vista之后, 开启DWM的情况下, 抓屏速度非常慢(30ms +), 具体原因不知道是因为系统没有缓存整个屏幕的数据还是GPU向内存拷贝数据太慢了, 有知道的朋友可以提示下。

2. Mirror driver

这种方法应该是Win8之前最高效的抓屏方法, 也是微软推荐的远程桌面共享方案,它通过创建虚拟镜像驱动, 直接获取最终屏幕变化数据。
该方法也有一些缺点:
a. 涉及到驱动安装, 技术难度大, 系统权限要求也高

b. Win8 上该方案已经失效

 

3. GDI hook

这种方法应该说是XP时代比较流行的抓屏方法, 因为所有的绘制都是通过GDI32.dll中的绘图函数来实现的, 所以我们只要拦截了这些函数, 系统的所有绘制就都让我们控制了。这种方法应该来说也是一种挺高效的抓屏方法,屏幕的变化也都能让我们拦截到, 同时因为好多绘图函数是以矢量方式实现的,所有抓到的数据包非常小, 即使在低带宽下也效果挺好。
下面是该方法的一些缺点:
a. Hook技术本身就有其复杂性和不稳定性, 尤其是Hook所有进程
b. Vista只有越来越多程序采用D2D/D3D绘制, GDI Hook对这些绘制无能为力。

c. Vista之后UAC打开的情况下, 如果我们的程序权限不够高, Hook不到更高权限的程序。

 

4. Windows Media API

Windows Media 9.0 支持用Windows Media Encoder 9 API来抓屏。它有一个编码器叫Windows Media Video 9 Screen codec,特别为抓屏优化过。Windows Media Encoder API提供了一个IWMEncoder2接口可以用来高效地捕捉屏幕图像。
因为对这组API不熟, 这种抓屏方法我也没尝试过, 具体可见Various methods for capturing the screen, 感觉这种方法的最大缺点是用户机器需要安装Windows Media Encoder 9。
 
5. DirectX

每个DirectX程序都包含一个被我们称作缓冲的内存区域,其中保存了和该程序有关的显存内容,这在程序中被称作后台缓冲(Back Buffer),有些程序有不止一个的后台缓冲。还有一个缓冲,在默认情况下每个程序都可以访问-前台缓冲。前台缓冲保存了和桌面相关的显存内容,实质上就是屏幕图像。 我们的程序通过访问前台缓冲就可以捕捉到当前屏幕的内容。上面的列子中也包含该方法的实现, 是基于DirectX9的,我们可以参考下。
Vista之后的DirectX 10/11相对于DirectX 9 已经发生非常大的变化, 直接用新的接口上面的代码未必能正常工作, 但是COM的优点就是我们可以在新的组件中依然调用老的接口。
 
6. PrintWindow

该方法本身不能直接做为一种抓屏方法, 但是有时候我们要获取某个窗口的内容, 即使他被其他窗口覆盖着, 这时候这个函数就很有用。该方该调用法的原理是通过给目标窗口发送WM_PRINT或是WM_PRINTCLIENT消息, 所以如果目标窗口没有响应, 该调用可能会阻塞抓屏线程, 这种情况下抓屏前最好先用SendMessageTimeout检测目标窗口是否有响应。另外该方法也抓不到D3D窗口的内容。
 
7. DWM/Dxgi hook

Vista之后微软放弃了XP时代的XPDM, 采用了全新的WDDM视屏驱动模型, 现在Win8.1上已经是WDDM1.3.
Vista之后底层所有的渲染都是基于D3D技术, 另外我们也知道系统在DWM.exe里进行窗口边框的绘画和合成, 所以理论上我们可以通过HOOK DWM/D3D/DXGI,拦截到整个系统的屏幕内容。当然作为一种Hook技术, 它也有上面GDI Hook类似的问题。
 
8. Magnification

这组API是微软Vista之后开放给我们开发放大镜程序的, 它里面提供了一个API让我们拦截到显示的内容, 可惜的是这个关键的API  MagSetImageScalingCallback 微软已经宣布作废。另外该方式的抓屏效率也不高, 整屏需要60 ms 左右。
 
9. Desktop Duplication  

这是微软Win8 上宣布放弃Mirror driver之后推荐采用的抓屏技术, 全部基于D3D/DXGI技术, 效率非常高, 并且包含变化区域和屏幕鼠标光标。它的缺点是没法抓取某个窗口的内容 。
 

 10. GetWindowDC 


该方法和PrintWindow类似,但是它没有PrintWindow的权限问题, 也没有超时问题。
这种抓屏方法在Win7/Win8  DWM打开的情况下抓屏,结果会颠覆我们XP时代的知识, 因为即使窗口被覆盖, 它也可以正确抓取到被覆盖窗口下的内容, WebRTC正是用这种方式来Share  Application的。
它的主要问题是有些窗口抓到的内容不包含非客户区,有些窗口比如任务栏的Thumbnail窗口会抓不到内容。
最后简单总结下 , 我们可以看到Windows系统上基本没有一种通用的抓屏技术可以高效的抓取所有的系统(XP/Win7/Win8), 很大一部原因是操作系统的显示驱动模型在从XPDM向WDDM转变, 应用层的API也在从GDI向D3D转变 。 相对于Linux的稳定, Window的不断发展和进步, 对开发人员究竟是喜是悲?

免责声明:文章转载自《Windows桌面共享中一些常见的抓屏技术》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇采用vue编写的功能强大的swagger-ui页面WinCE串口蓝牙的实现 .下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

Windows10更新系统后,无法打开VMware

windows推送更新系统,更新完之后vmware就不能用了,打开如下图所示: 解决方案 1.win10打开—>此电脑—>属性—>打开控制面—>程序—>查看已安装的更新 点击‘“查看已安装的更新” 2,找到windows的最近更新补丁,右键,点击“卸载”。 3、卸载需要时间,卸载后“立即重启计算机” 4、重启后重新打开VM虚...

WindowsAPI笔记(一)

句柄 在Windows应用程序中,窗口是通过窗口句柄(HWND)来标识的。我们要对某个窗口进行操作,首先就要得到这个窗口的句柄。句柄(HANDLE)是Windows程序中一个重要的概念,使用也非常频繁。在Windows程序中,有各种各样的资源(窗口、图标、光标等),系统在创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,即句柄。在后面的内容中我们...

ios 图片点击两次禁止保存或拷贝

通常当你在手机或者pad上长按图像 img ,会弹出选项 存储图像 或者 拷贝图像,如果你不想让用户这么操作,那么你可以通过以下方法来禁止:   img{ -webkit-touch-callout:none;   } PS:需要注意的是,该方法只在 iOS 上有效。...

STM32自己的封装库

以前一直使用STM32的标准库,需要一步步地将代码加进去,将编译选项设置好,然后再编译整个工程。 这个编译过程是一个相当慢的过程!完全编译大约需要一支烟的时间。每次建立工程都这么编译,是一个相当浪费时间和香烟的过程。 于是,我有了将库编译成lib文件的想法。本博文就是我将STM32F4的标准库编译成lib文件并在工程中使用的过程。 适用对象: 1、熟悉库...

Windows下改变右键新建菜单中“文本文档”名称方法

我个人比较喜欢用快捷键,经常新建.txt文件,以前用英文版XP时,只需在桌面或文件夹空白位置点击右键,然后按键盘“W”(New),再按“T”(Text Document),就可以新建.txt文件了,而且平时左手就放在键盘上,如此操作连着来就很快很方便。但是在中文版系统中,新建菜单里是“文本文档”,按“T”时没有用,需要鼠标移动过去,因此觉得效率较低。 通过...

双系统安装 Windows8和Windows Server2012

亲自实践 第一种方法: 首先要有一个U盘启动比如用大白菜制作一个U盘启动,制作完之后,然后将下载的win8镜像文件解压到你的本地磁盘,重新启动电脑,然后把U盘设为第一启动盘,在重启,进入winPE系统,那个大白菜制作的PE系统是2003的这道不所谓了,启动起来桌面上有个Win7安装器,也就是nt6启动软件如下图 然后点击图中的打开按钮,在这里打开你刚才解...