C#使用PrintWindow捕获隐藏/非活跃游戏窗口异常问题求助
解决方案
问题根源
现代游戏大多使用DirectX/OpenGL等硬件加速技术渲染画面,这些画面直接输出到显卡帧缓冲区,而非通过GDI绘制链路。PrintWindow默认调用只能捕获GDI绘制的内容,因此无法获取游戏的实际渲染画面。
方法1:使用PrintWindow的全屏渲染标志
尝试调用PrintWindow时传入PW_RENDERFULLCONTENT(值为0x00000002),该标志会强制窗口渲染完整内容,对部分支持此机制的游戏有效。
修改代码步骤:
- 添加常量定义:
private const uint PW_RENDERFULLCONTENT = 0x00000002;
- 修改
PrintWindow调用:
PrintWindow(handle, hdcBitmap, PW_RENDERFULLCONTENT);
方法2:使用Windows Graphics Capture API(推荐Win10及以上系统)
这是微软针对现代应用和硬件加速窗口设计的官方捕获方案,支持捕获非活跃、被遮挡的窗口,无需特殊权限,兼容性更好。
示例代码核心逻辑:
using Windows.Graphics.Capture; using Windows.Graphics.DirectX; using Windows.Graphics.DirectX.Direct3D11; using System.Drawing; using System.Drawing.Imaging; public static async Task<Bitmap> CaptureGameWindowAsync(IntPtr hwnd) { // 通过窗口句柄获取捕获项 var captureItem = GraphicsCaptureItem.TryCreateFromWindowId(Win32Interop.GetWindowIdFromWindow(hwnd)); if (captureItem == null) return null; // 创建Direct3D设备 var d3dDevice = Direct3D11Helper.CreateDevice(); // 创建帧池 var framePool = Direct3D11CaptureFramePool.Create( d3dDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 1, captureItem.Size); // 创建捕获会话并启动 var captureSession = framePool.CreateCaptureSession(captureItem); captureSession.StartCapture(); // 获取捕获帧 var captureFrame = await framePool.TryGetNextFrameAsync(); if (captureFrame == null) { captureSession.Dispose(); framePool.Dispose(); return null; } // 将Direct3D表面转换为Bitmap var bitmap = BitmapFromDirect3DSurface(captureFrame.Surface); // 释放资源 captureFrame.Dispose(); captureSession.Dispose(); framePool.Dispose(); return bitmap; } // 辅助方法:将Direct3D Surface转换为GDI Bitmap public static Bitmap BitmapFromDirect3DSurface(IDirect3DSurface surface) { using (var stream = new InMemoryRandomAccessStream()) { var encoder = BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream).AsTask().Result; encoder.SetSoftwareBitmap(SoftwareBitmap.CreateCopyFromSurface(surface, BitmapAlphaMode.Premultiplied)).AsTask().Wait(); encoder.FlushAsync().AsTask().Wait(); stream.Seek(0); return new Bitmap(stream.AsStream()); } }
注:需要项目支持.NET 5+或添加WinRT包引用,具体可参考微软官方文档。
方法3:Direct3D钩子捕获(进阶方案)
对于不支持Windows Graphics Capture的老旧游戏,可以通过钩子IDXGISwapChain::Present方法拦截游戏的帧渲染,直接从显卡获取帧数据。这种方法需要深入掌握Direct3D编程知识,适合对性能要求较高的场景。
内容的提问来源于stack exchange,提问作者Сергей
相关产品推荐
相关产品推荐

