在直播项目中 需要捕获某个窗口的画面并共享 总结了如下几种场景中窗口的捕获方法
1、dc拷贝(BitBlt、PrintWindow)
这是最基本的方法 直接拿到窗口dc 然后从dc中拷贝窗口画面。PrintWindow可以捕获窗口超出桌面范围的区域。需要注意的是,PrintWindow会触发目标窗口执行WM_PAINT,并且执行完毕后才会返回,所以可能造成目标窗口频繁刷新,或调用PrintWindow会耗时(目标窗口执行完WM_PAINT才会返回),所以不推荐使用这个API。
关键词:GetDC BitBlt GetDIBits PrintWindow
2、具有WS_EX_LAYERED属性的窗口
比如酷狗歌词窗口、BigFoot界面(魔兽世界大脚),这种窗口第一种方法是拿不到画面的(拿到的画面是黑色)。
只能通过“dll进程注入+API函数hook”的方法 在hook了的API(UpdateLayeredWindow或UpdateLayeredWindowIndirect)的回调函数中,通过参数HDC获取到窗口画面。
3、使用OpenGL/D3D/Vulkan渲染的窗口
不少游戏(CS/QQ桌球/英雄联盟)和播放器的界面渲染 就是使用OpenGL/D3D/Vulkan进行渲染的,
当游戏是全屏模式时,与方法2一样 也只能通过“dll进程注入+API函数hook”的方法进行画面捕获。
其中OpenGL的hook比较简单 直接hook渲染函数wglSwapBuffers并在回调中解析数据就行了。
但是D3D 因为版本太多 针对不同的游戏 需要hook对应的D3D版本:D3D9 D3D10 D3D11 D3D12。
针对不同版本的D3D hook对应的渲染函数 实现起来工作量相对较多
4、UWP窗口/Chrome/Office(sdk至少需要Windows 10 SDK version 10.0.18362.0)
详见windows官方sample https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/tree/master/cpp/ScreenCaptureforHWND