This topic is now archived and is closed to further replies.


How to capture a surface of a DirectX game?

Recommended Posts

1024B    122
There is a DirectX game running in exclusive mode, and I wan''t to capture the primary surface in my code.What to do? Print Screen is too slow, is there some "Direct" way? Thanks.

Share this post

Link to post
Share on other sites
1024B    122
I have successfully capture the primary surface of null-exclusive Directx application in this way:

Set my code to exclusive mode.
Create a primary surface.
Lock it.
Write to a DIB.

But this won''t work if it is a Directx game,since the game is in
exclusive mode.

Any idea?

Share this post

Link to post
Share on other sites
NeonGE    140

void CGraficos::GrabaScreenShot(char* NombreArchivo)
//Creamos un puntero al front buffer
IDirect3DSurface8* FrontBuffer;

//Extraemos las medidas del dispositivo

//Ahora creamos la superficie en la que se copiara nuestra imagen
//La superfice del front buffer es D3DFMT_A8R8G8B8 cuando es regresada
m_pD3DDevice->CreateImageSurface(vp.Width, vp.Height, D3DFMT_A8R8G8B8, &FrontBuffer);

//Ahora copiamos el front buffer a nuestra superficie
HRESULT hr = m_pD3DDevice->GetFrontBuffer(FrontBuffer);

if(hr != D3D_OK)
{//Si fallo al obtener el front buffer
FrontBuffer->Release(); //Liberamos la superficie para evitar memory leaks
return;//Salimos de la funcion

//Ahora escribimos la informacion en un bitmap
D3DXSaveSurfaceToFile(NombreArchivo, D3DXIFF_BMP, FrontBuffer, NULL, NULL);


Share this post

Link to post
Share on other sites
Darrell L    122
Are you trying to grab a screenshot for your own app or anothers? NeonGE''s method works for your own app.

If you want to grab a screenshot of another app that''s currently running, try the following. You''ll probably want to change the Sleep to a hotkey usage but everything else will be the same:

#include <windows.h>

PBITMAPINFO CreateBitmapInfoStruct( HBITMAP hBmp );
void CreateBMPFile( LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC );

int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow )

// HWND hWnd = GetForegroundWindow();
HWND hWnd = GetDesktopWindow();
if( hWnd ) {
HDC hWC = GetDC(hWnd);
GetClientRect(hWnd, &rW);
if( hWC ) {
HDC hDC = CreateCompatibleDC(hWC);
if( hDC ) {
HBITMAP hBitmap = CreateCompatibleBitmap(hWC, rW.right, rW.bottom);
if( hBitmap ) {
HGDIOBJ hBMOld = SelectObject(hDC, hBitmap);
BitBlt(hDC, 0, 0, rW.right, rW.bottom, hWC, 0, 0, SRCCOPY);
PBITMAPINFO pBMI = CreateBitmapInfoStruct(hBitmap);
if( pBMI ) {
CreateBMPFile("screengrab.bmp", pBMI, hBitmap, hDC);
ReleaseDC(hWnd, hWC);
return 0;

PBITMAPINFO CreateBitmapInfoStruct( HBITMAP hBmp )
WORD cClrBits;

// Retrieve the bitmap''s color format, width, and height.
GetObject(hBmp, sizeof(BITMAP), (LPSTR)&bmp);

// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);

if( cClrBits == 1 ) cClrBits = 1;
else if( cClrBits <= 4 ) cClrBits = 4;
else if( cClrBits <= 8 ) cClrBits = 8;
else if( cClrBits <= 16 ) cClrBits = 16;
else if( cClrBits <= 24 ) cClrBits = 24;
else cClrBits = 32;

// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)

if( cClrBits < 24 )
sizeof(RGBQUAD) * (1 << cClrBits));

// There is no RGBQUAD array for the 24 bpp or 32 bpp format.

// Initialize the fields in the BITMAPINFO structure.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;

if( cClrBits < 24 )
// if( cClrBits < 16 )
pbmi->bmiHeader.biClrUsed = 1 << cClrBits;

// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;

// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
pbmi->bmiHeader.biSizeImage = (pbmi->bmiHeader.biWidth + 7) / 8
* pbmi->bmiHeader.biHeight*cClrBits;

// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;

return pbmi;

void CreateBMPFile( LPTSTR pszFile, PBITMAPINFO pbi, HBITMAP hBMP, HDC hDC )
HANDLE hf; // file handle
BITMAPFILEHEADER hdr; // bitmap file-header
PBITMAPINFOHEADER pbih; // bitmap info-header
LPBYTE lpBits; // memory pointer
DWORD dwTotal; // total count of bytes
DWORD cb; // incremental count of bytes
BYTE *hp; // byte pointer
DWORD dwTmp;

lpBits = (LPBYTE)GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);

// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if( pbih->biBitCount < 24 )
GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight, lpBits, pbi, DIB_PAL_COLORS);
GetDIBits(hDC, hBMP, 0, (WORD)pbih->biHeight, lpBits, pbi, DIB_RGB_COLORS);

// Create the .BMP file.
hf = CreateFile(pszFile, GENERIC_READ | GENERIC_WRITE, (DWORD) 0, NULL,

hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"

// Compute the size of the entire file.
hdr.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;

// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + pbih->biSize + pbih->biClrUsed
* sizeof(RGBQUAD);

// Copy the BITMAPFILEHEADER into the .BMP file.
WriteFile(hf, (LPVOID)&hdr, sizeof(BITMAPFILEHEADER), (LPDWORD)&dwTmp, NULL);

// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
WriteFile(hf, (LPVOID)pbih, sizeof(BITMAPINFOHEADER) +
pbih->biClrUsed * sizeof(RGBQUAD), (LPDWORD)&dwTmp, NULL);

// Copy the array of color indices into the .BMP file.
dwTotal = cb = pbih->biSizeImage;
hp = lpBits;

WriteFile(hf, (LPSTR)hp, (int)cb, (LPDWORD)&dwTmp, NULL);

// Close the .BMP file.

// Free memory.

Share this post

Link to post
Share on other sites