Ways to capture the screen


Capturing the screen (or put another way, creating an in-memory copy of the image currently being displayed on the screen, for re-display, printing, or later saving) is a task with many different solutions.  I'll try to enumerate the possibilities below.  This isn't a perfect or complete list, but it covers the best supported ways, and lists some of their drawbacks.

1 - Use the Desktop Duplication API.  This is a very powerful and full-featured API, which provides access to every frame of desktop update, BUT, it is not available prior to Windows 8.

One drawback is that most full-screen exclusive mode DirectX or OpenGL applications will not be able to be captured with Desktop Duplication.  Exclusive mode really means that the ‘Windowed’ field of D3DPRESENT_PARAMETERS is set to false.  Some apps are not in true full-screen mode and are windowed, but with the window set to the size of the desktop.  These can still be captured.

To make matters a little more confusing, newer DirectX (11.1 and later) exclusive mode apps can be captured with the Desktop Duplication API, unless they "opt-out" and specifically disallow it (in which case they won't be capture-able by Desktop Duplication, just like a pre-11.1 DirectX app).

2 - The old standby, GDI, can still capture the screen.  Typically, BitBlt is used.  This technique is not perfect, and there are some things, such as multimedia output, that won't get captured.

BitBlt can also can be slow, although you can get much better performance by making sure that the bitmap (that you are capturing into) is the same resolution as the screen.  To assure this, you could use CreateCompatibleBitmap (for a device-dependent bitmap), or CreateDIBSection (for a device-independent bitmap).  If you use CreateDIBSection, just make sure the bit-depth and layout matches the screen's.  This allows BitBlt to avoid any color conversion, which can drastically slow everything down.  Here's what such code might look like from a high level...

// Pseudo-code...

HDC hDCScreen = GetDC(NULL);

HDC hDCMem = CreateCompatibleDC(hDCScreen);

HBITMAP hBitmap = CreateCompatibleBitmap(hDCScreen, screenwidth, screenheight);

SelectObject(hDCMem, hBitmap);

BitBlt(hDCMem, 0, 0, screenwidth, screenheight, 0, 0, SRCCOPY);

 

3 - Another option is to use Direct3D.  Note that some have reported that this can actually be slower than BitBlt, but performance of any technique will depend a lot on the hardware and graphics settings (regardless of the method used).  To do this with Direct3D, you could use GetRenderTargetData to copy the rendering surface (retrieved with GetRenderTarget) to an off-screen surface (which can be created with CreateOffscreenPlainSurface).  After copying the surface data this way, you can save the contents of the surface to a file using D3DXSaveSurfaceToFile.

 

4 - Yet another possibility is to use Windows Media technologies to do the capture (specifically, Expression Encoder will do this if you just need another application).  To do it programmatically yourself (using Windows Media), you can use the Windows Media Video 9 Screen codec.

 

5 - Finally, for pre-Windows 8 systems, you could develop a Mirror Driver to do this (Windows 8 uses another driver model, which is also described under the preceding link).

 

Some of the above techniques (particularly #2 and #3) can also be used to capture only a single window.  Note that iif you use BitBlt to do this, you could "or in" the CAPTUREBLT flag if you wanted to capture windows that are layered on top of your window .  The PrintWindow API is another good option for capturing only a single window (not listed above since it can't capture the entire screen).

 


Comments (5)
  1. John Schroedl says:

    A good overview. I was not aware of the new Desktop Duplication API.. will have to check that out! Thanks.

  2. jtomczyk says:

    Hi Dave,

    I have struggled using option #3 – GetRenderTarget combined with GetRenderTargetData. All that I get is a black screen. Can you please tell me the D3DPRESENT_PARAMETERS that you used when creating your direct3d device?

    Regards,

    Joe Tomczyk

  3. roger says:

    So is there any easy way (like BitBlt is easy) to capture the screen including windows directx applications?

  4. CAPTUREBLT in Windows 8 says:

    The CAPTUREBLT flag does not appear do anything in Windows 8.1. I'd like to not capture the layered windows. Is there another flag I can use?

  5. lc says:

    Thank you so much for your article. Lots of good tips!

    Nothing to do with you, but I must say aiiieeeee none of these are particularly great for capturing video games. I suddenly see now why everybody gives up and injects the DX DLLs. It's the only method that reliably works, gives fast performance and is easy to implement. DLL injection should *never* be the preferred route for anything, it's just not legit. I assume most of the insane limitations are in interest of copy-protection of DVDs. Doesn't anyone realize that if I want to pirate a movie I can just point a camera at the screen? I quick-preview my own work to clients that way over my phone.

    I just want to real-time capture my game play for science reasons. 🙁 Much sad. 🙁

Comments are closed.

Skip to main content