如何通过GDI与HWND获取Chrome Intermediate D3D Window窗口图像
问题说明
Windows 10环境下使用C#调用gdi32.dll,通过进程窗口句柄获取窗口图像的原有GDI实现代码如下:
DC = GetWindowDC(HWND); CDC = CreateCompatibleDC(DC); CB = CreateCompatibleBitmap(DC, 1920, 1080); SelectObject(CDC, CB); BitBlt(CDC, 0, 0, 1920, 1080, DC, 0, 0, SRCCOPY); GetBitmapBits(CB, 1920*1080*4, BitImageArray);
上述逻辑执行完成后,BitImageArray[]会被填充图像的RGBA数据,在绝大多数常规窗口场景下运行正常。但捕获开启GPU加速的Chrome窗口时会失效:通过SPY++查看该状态下Chrome窗口类名为Intermediate D3D Window,关闭GPU加速后窗口类名变为Chrome Legacy Window,此时上述截图代码可正常运行,但业务要求目标页面必须开启GPU加速才能正常展示,无法通过关闭GPU加速的方式绕过问题。
失效原因
传统GDI的BitBlt接口只能捕获通过GDI管线绘制到窗口DC的内容。Chrome开启GPU加速后,页面内容通过Direct3D直接渲染到GPU侧的交换链,对应承载渲染内容的Intermediate D3D Window不会把渲染结果提交到GDI设备上下文,因此GDI截图只能拿到空白/黑帧。
可行实现方案
- Windows Graphics Capture API方案(推荐)
这是Win10 1803及以上版本提供的系统原生捕获接口,专门适配GPU加速渲染的窗口、显示器捕获场景,不需要注入目标进程,不需要修改Chrome配置,能完整拿到D3D窗口的渲染内容,捕获性能高、无黑帧问题。C#可直接通过WinRT调用该接口,传入目标窗口句柄即可获取原始帧数据,拿到的帧可直接映射为CPU可访问的RGBA数组,适配原有BitImageArray的逻辑成本极低。 - PrintWindow接口最小改动方案
可以直接替换原有BitBlt调用为PrintWindow接口,传入PW_RENDERFULLCONTENT标志(参数值为2),强制系统捕获窗口的D3D渲染内容,核心改动代码如下:
该方案代码改动量最小,但存在兼容性缺陷:部分Chrome版本下会出现窗口边框偏移、内容截断问题,Win10早期版本可能依然无法正常捕获D3D窗口内容。// 替换原有BitBlt(CDC, 0, 0, 1920, 1080, DC, 0, 0, SRCCOPY); 调用 PrintWindow(HWND, CDC, 2); - DXGI Desktop Duplication方案
该接口属于DirectX图形基础设施的一部分,可直接从GPU侧获取桌面输出的完整帧,再根据目标窗口的位置、尺寸从桌面帧中裁剪出对应窗口的图像数据。该方案捕获性能最高,适合高帧率连续截图场景,但无法穿透遮挡:如果目标窗口被其他窗口覆盖、或者处于最小化状态,裁剪得到的内容会包含遮挡层的画面,仅适合目标窗口置顶、无遮挡的使用场景。
不推荐使用DLL注入Chrome进程Hook D3D交换链的方案,Chrome自带沙箱与进程保护机制,注入极易触发进程崩溃,且Chrome版本迭代频繁,渲染进程结构变动大,方案维护成本极高。
内容的提问来源于stack exchange,提问作者BloodAndCat
相关产品推荐
相关产品推荐

