Windows API问题:捕获第三方Unity窗口画面返回缓存内容
解决方案:Unity窗口截图缓存问题修复
问题根源
Unity窗口依赖Direct3D等硬件加速渲染,常规GDI的BitBlt仅能捕获窗口的GDI兼容缓存层,无法获取实时渲染的画面。而PrintWindow API可主动请求窗口将自身内容绘制到指定DC,更适配这类硬件加速窗口的捕获需求。
修改方案
将原代码中的BitBlt调用替换为PrintWindow,并调整相关逻辑:
1. 补充User32接口的PrintWindow方法
确保JNA的User32接口包含PrintWindow方法(无则添加):
interface User32 extends StdCallLibrary { User32 INSTANCE = Native.load("user32", User32.class); // ... 保留原有其他方法 ... boolean PrintWindow(HWND hWnd, HDC hdcBlt, int nFlags); }
2. 替换截图核心逻辑
将原代码中BitBlt的调用部分替换为PrintWindow:
原代码片段:
if (!GDI32.INSTANCE.BitBlt(hdcTargetMem, 0, 0, windowWidth, windowHeight, hdcTarget, 0, 0, GDI32.SRCCOPY)) { throw new Win32Exception(Native.getLastError()); }
替换为:
// 使用PrintWindow捕获窗口完整内容,传入0表示捕获整个窗口 if (!User32.INSTANCE.PrintWindow(target, hdcTargetMem, 0)) { throw new Win32Exception(Native.getLastError()); }
修改后完整的getScreenshot方法(关键部分)
// ... 原有代码:获取窗口矩形、创建DC和Bitmap等逻辑保持不变 ... try { hdcTargetMem = GDI32.INSTANCE.CreateCompatibleDC(hdcTarget); if (hdcTargetMem == null) { throw new Win32Exception(Native.getLastError()); } hBitmap = GDI32.INSTANCE.CreateCompatibleBitmap(hdcTarget, windowWidth, windowHeight); if (hBitmap == null) { throw new Win32Exception(Native.getLastError()); } hOriginal = GDI32.INSTANCE.SelectObject(hdcTargetMem, hBitmap); if (hOriginal == null) { throw new Win32Exception(Native.getLastError()); } // 核心替换:用PrintWindow替代BitBlt if (!User32.INSTANCE.PrintWindow(target, hdcTargetMem, 0)) { throw new Win32Exception(Native.getLastError()); } // ... 原有代码:获取DIBits、转换为BufferedImage等逻辑保持不变 ... } // ... 原有finally块和异常处理逻辑保持不变 ...
额外注意事项
- 若只需捕获窗口客户区(排除标题栏),可将
PrintWindow第三个参数改为1(需自行定义常量:static final int PW_CLIENTONLY = 1;)。 - 确保目标Unity窗口处于非最小化状态,
PrintWindow无法捕获最小化窗口的内容。 - 若仍存在画面延迟,可在调用
PrintWindow前触发窗口重绘:
User32.INSTANCE.SendMessage(target, WinUser.WM_PAINT, 0, 0);
内容的提问来源于stack exchange,提问作者Mysteryy
相关产品推荐
相关产品推荐

