如何在C#中捕获全屏3D游戏(如Crossfire)的截图?
Hey Paul, I totally get how frustrating it is to scour the internet for a working solution and come up empty—capturing fullscreen games like Crossfire is way trickier than regular window screenshots because they rely on hardware-accelerated APIs like DirectX/OpenGL, which are off-limits to basic GDI+ methods. Let’s dive into a few C#-based solutions that actually work for this scenario:
This is Microsoft's modern screen capture API, designed to handle hardware-accelerated windows without extra dependencies. It's clean and reliable for newer systems.
using Windows.Graphics.Capture; using Windows.Graphics.DirectX; using Windows.Graphics.DirectX.Direct3D11; using Windows.Storage.Streams; using System.Threading.Tasks; using System.Drawing; using System.Drawing.Imaging; using SharpDX.Direct3D11; using SharpDX.Direct3D; public async Task CaptureFullscreenGameWithWGC() { // Capture the entire primary monitor (targets fullscreen games) var targetMonitor = GraphicsCaptureMonitor.GetCurrentMonitor(); var captureItem = GraphicsCaptureItem.CreateFromMonitor(targetMonitor); // Initialize capture frame pool and session var d3dDevice = CreateD3DDevice(); var framePool = Direct3D11CaptureFramePool.Create( d3dDevice, DirectXPixelFormat.B8G8R8A8UIntNormalized, 2, captureItem.Size); var captureSession = framePool.CreateCaptureSession(captureItem); captureSession.StartCapture(); // Fetch the captured frame var frame = await framePool.TryGetNextFrameAsync(); var surface = frame.Surface; // Convert D3D surface to a Bitmap for saving using (var stream = new InMemoryRandomAccessStream()) { var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream); encoder.SetPixelData( BitmapPixelFormat.Bgra8, BitmapAlphaMode.Ignore, (uint)surface.Description.Width, (uint)surface.Description.Height, 96, 96, await ExtractPixelDataFromSurface(surface)); await encoder.FlushAsync(); stream.Seek(0); using (var bitmap = new Bitmap(stream.AsStream())) { bitmap.Save("crossfire_screenshot.png", ImageFormat.Png); } } captureSession.StopCapture(); } // Helper: Create a D3D11 device for WGC private static Direct3D11Device CreateD3DDevice() { var dxDevice = new Device(DriverType.Hardware); return Direct3D11Device.CreateFromDXGIAdapter(dxDevice.Adapter); } // Helper: Extract raw pixel data from D3D surface private static async Task<byte[]> ExtractPixelDataFromSurface(IDirect3DSurface surface) { var d3dSurface = surface as Direct3D11Surface; var texture = d3dSurface.NativeObject as Texture2D; var mappedResource = texture.Device.ImmediateContext.MapSubresource(texture, 0, MapMode.Read, MapFlags.None); var pixelBytes = new byte[mappedResource.RowPitch * texture.Description.Height]; System.Runtime.InteropServices.Marshal.Copy(mappedResource.DataPointer, pixelBytes, 0, pixelBytes.Length); texture.Device.ImmediateContext.UnmapSubresource(texture, 0); return pixelBytes; }
Note: You'll need to install the Microsoft.Windows.SDK.Contracts and SharpDX.Direct3D11 NuGet packages to access these APIs.
If you need support for Win7/Win8, this method taps into Direct3D 9's backbuffer to grab game frames. It uses the SharpDX library to simplify C# interactions with DirectX.
First, install the SharpDX.Direct3D9 NuGet package, then use this code:
using SharpDX.Direct3D9; using System.Drawing; using System.Drawing.Imaging; using System.Diagnostics; using System; public void CaptureDirectX9Game() { // Get Crossfire's window handle (adjust process name if needed) var crossfireProcess = Process.GetProcessesByName("crossfire")[0]; var gameWindowHandle = crossfireProcess.MainWindowHandle; // Initialize D3D9 device targeting the game window var presentParams = new PresentParameters { Windowed = false, SwapEffect = SwapEffect.Discard, DeviceWindowHandle = gameWindowHandle, BackBufferFormat = Format.A8R8G8B8 }; using (var d3d = new Direct3D()) using (var device = new Device(d3d, 0, DeviceType.Hardware, gameWindowHandle, CreateFlags.HardwareVertexProcessing, presentParams)) { // Grab the backbuffer surface using (var backBuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono)) { // Convert surface to Bitmap var screenshot = new Bitmap(backBuffer.Description.Width, backBuffer.Description.Height, PixelFormat.Format32bppArgb); var bitmapRect = new Rectangle(0, 0, screenshot.Width, screenshot.Height); var bitmapData = screenshot.LockBits(bitmapRect, ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); backBuffer.LockRectangle(LockFlags.None, out var lockedSurface); System.Runtime.InteropServices.Marshal.Copy(lockedSurface.DataPointer, bitmapData.Scan0, 0, bitmapData.Stride * screenshot.Height); backBuffer.UnlockRectangle(); screenshot.UnlockBits(bitmapData); screenshot.Save("crossfire_dx9_screenshot.png", ImageFormat.Png); } } }
Pro Tip: Run your application as administrator if you hit access denied errors—some games restrict capture from non-elevated processes.
- Avoid using
Graphics.CopyFromScreen()entirely—it can't access hardware-accelerated game frames stored in VRAM. - If Crossfire uses anti-capture measures, try disabling overlays (like Steam/Origin overlays) before running your capture tool.
- For true fullscreen exclusive mode, the Windows Graphics Capture monitor capture method is more reliable than window-targeted capture.
内容的提问来源于stack exchange,提问作者Paul Garcia

