文档章节

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

山水-黄
 山水-黄
发布于 2017/08/15 18:37
字数 1712
阅读 21
收藏 1

本篇博客内容是属于转载的,原文地址:

http://www.cppblog.com/weiym/archive/2013/12/01/204536.aspx

 

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 上该方案已经失效, 但是还是有方法的, 参见 Remote Display Drivers

 

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的,我们可以参考下, 据我测试该方法在DWM打开的情况下抓整屏也要30ms左右。Vista之后的DirectX 10/11相对于DirectX 9 已经发生非常大的变化, 直接用新的接口上面的代码未必能正常工作。


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的不断发展和进步, 对开发人员究竟是喜是悲?

 

另外还有一篇博文值得参考学习,该博文仔细的介绍了几种抓屏的方式:

http://blog.csdn.NET/henry19850318/article/details/5732106

本文转载自:http://www.cppblog.com/weiym/archive/2013/12/01/204536.aspx

共有 人打赏支持
山水-黄
粉丝 1
博文 20
码字总数 26458
作品 0
广州
程序员
C++编程 使用QT5 SDK录制屏幕并显示

在项目中,我们有要录制屏幕的需求,录制屏幕有多种方法,可以基于windows api的BitBlt 、ffmpeg的AVDevice、directx 和QT,本文讲解基于QT5的抓屏。QT相对于其他几种抓屏方式优势是跨平台做...

夏曹俊
2017/07/27
0
0
倪光南院士:国产桌面操作系统最快10月份发布

近日,中国工程院院士倪光南在一次小型媒体见面会上向《人民邮电》报记者表示,国产操作系统的突破,将首先从桌面操作系统开始,我国今年10月有望推出支持应用商店的国产桌面操作系统新版本。...

oschina
2014/08/23
7K
100
obs-studio源码分析(一):窗口、显示器(桌面)捕捉

windows下窗口、桌面捕捉有多种方式。如下: 1:使用GDI函数或者Windows Media API函数 2:使用DirectX技术 3:使用api hook技术(如D3D游戏捕捉) 4:使用图形驱动技术 obs的窗口、桌面捕捉...

balijinyi
05/11
0
0
Windows 7 与 Windows 8 之间的 7 大变化

微软“臭名昭著”的Patch Tuesday 9日被Update Tuesday取代,该公司要彻底转向Windows 8和其核心应用程序。 Windows 7与Windows8之间的7大变化如下: 1. 桌面与用户界面:Windows 8采用基于微...

oschina
2012/10/11
5.3K
21
如何规划构建一套大型的Citrix桌面虚拟化架构 - Part1

Part2:http://kaiqian.blog.51cto.com/236001/1717010 Part3:http://kaiqian.blog.51cto.com/236001/1717024 Part4:http://kaiqian.blog.51cto.com/236001/1717064 后记:http://kaiqian.......

技术小胖子
2017/10/31
0
0

没有更多内容

加载失败,请刷新页面

加载更多

python做文本内容指定区域字符串替换

需求: 因为公司项目需要做SEO优化,所以对项目中的各种长连接做优化,比如本文中提到的精简路径;之前已经批量吧文本的路径名字等做过修改,这里不再赘述;这里的问题是外部的路径修改了,文...

坦途abc
39分钟前
3
0
MySQL 关键字模糊匹配,并按照匹配度排序

MySQL 关键字模糊匹配,并按照匹配度排序。 方式一、按照关键字搜索,然后根据关键字所占比例排序 SELECTdrug_name,pinyinFROMtbl_drugWHEREpinyin LIKE '%AM%'ORDER BY...

yh32
49分钟前
3
0
虚拟机学习之一:java内存区域与内存溢出异常

1.运行时数据区域 java虚拟机在执行java程序的过程中会把它所管理的内存划分为若干个不同的数据区域。这些区域都有各自的用途和创建、销毁时间,有的区域伴随虚拟机进程的启动而存在,有些区...

贾峰uk
50分钟前
0
0
Spring加载properties文件的两种方式

在项目中如果有些参数经常需要修改,或者后期可能需要修改,那我们最好把这些参数放到properties文件中,源代码中读取properties里面的配置,这样后期只需要改动properties文件即可,不需要修...

架构师springboot
今天
1
0
分布式事务,原来可以这么玩?

多个数据要同时操作,如何保证数据的完整性,以及一致性? 答 : 事务 ,是常见的做法。 举个栗子: 用户下了一个订单,需要修改 余额表 , 订单 表 , 流水 表 ,于是会有类似的伪代码: st...

微笑向暖wx
今天
2
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部