最近工作 中有个需求是抓取桌面截图, 这里的桌面是指点了“显示桌面”之后看到的桌面, 截图内容包括桌面背景和图标以及任务栏,如下图: 


注意需求是:即使当前其他窗口盖在我们的桌面上,我们要求抓取到的内容也是这些窗口背后的桌面。


思考怎么样才能在程序运行时,动态抓取该截图?

大概想了些方法:

(1) 通过Desktop DC, 然后BitBlt
点评: 通过这种方法抓取到的截图是当前桌面的所有窗口,包括其他当前打开显示的窗口 , 这不是我们所期望的。
另外我们也不可能在需要截图时最小化所有窗口, 截完了再还原。

(2)通过注册表获取桌面壁纸保存的地方
点评:获取到该壁纸, 没有图标和任务栏, 也不是我们所期望的。

(3)通过DWM特性来获取
点评: Vista后的Desktop Window Manager(DWM)特性,可以让我们通过DwmRegisterThumbnail,DwmUpdateThumbnailProperties等API实时显示某个窗口的截图。可惜获取到的内容只能显示在我们预定义的窗口里, 但是我们没法获取里面的内容。另外这个特性只有Vista之后才支持, XP系统怎么办?

(4)通过Magnification来获取
点评:我们可以通过系统的放大镜技术,
过滤掉盖在桌面上的其他窗口(MagSetWindowFilterList),然后通过MagSetImageScalingCallback拦截内容。该技术的问题一是过滤窗口的个数限制, 另外也只能适用于Vista之后。

(5)通过API Hook技术
点评:通过API Hook技术我们可以动态拦截桌面窗口DC的绘画动作,这样就可以拦截或是合成窗口内容了。但是一来这样做比较复杂, 稳定性也很难保证,另外也有杀鸡用牛刀的感觉。

(6)通过PrintWindow技术
点评:PrintWindow API内部通过WM_PRINTCLIENT和WM_PRINT来获取窗口截图, 这个API在XP时代工作的不是很好,但是在Vista之后已经比较稳定了。

我们最后选择通过PrintWindow API来获取桌面截图, 大概过程如下: 
a. 获取桌面窗口(Program Manager)的内容
b. 获取TaskBar窗口的位置和内容
c. 把TaskBar窗口内容和桌面内容合成, 贴在正确的位置

这里说一下要注意的一些问题: 

a . 注意窗口的层次

Aero模式下, Program Manager窗口只包含背景图片, 图标列表在WorkerW窗口下:

Basic模式下窗口内容都在Program Manager窗口下:


b. 注意多显示器的情况, 多显示器时除了主显示器,其他显示器桌面是没有任务栏的

c. 注意任务栏的位置, 任务栏是可以Dock到任何地方并且以隐藏的,不要hard code在下面了。

d.  XP下对ProgramManager窗口调用PrintWindow会有刷新问题。一直没有好的解决方案, 所以对XP勉强采用第一种DC的方式了。

因此, 我到现在还没有找到完整解决我们这个问题的方法, 不知道大家有没有好的思路?

附上我的测试代码:ScreenSnapshot.rar
posted on 2013-08-30 20:30 Richard Wei 阅读(7800) 评论(2)  编辑 收藏 引用 所属分类: windows desktop

FeedBack:
# re: 如何获取桌面截图
2013-09-02 17:16 | 笨笨熊
发一个显示桌面的命令,然后再截图,最后再发一个显示桌面的命令。。。Over。。。  回复  更多评论
  
# re: 如何获取桌面截图
2013-09-02 17:52 | Richard Wei
@笨笨熊
基本不可能, 这个用户体验也太差了吧  回复  更多评论
  

只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理