Capturing a Window Image Into a Bitmap File, Supporting MS PaintBrush and All -- (Like the Thumbnail View of Windows Explorer)

Environment: VC++


I have written this article to capture a Windows image into a bitmap file that will support all PaintBrush tools and Thumbnail Views of Windows Explorer. I have found many programmers suffering from this problem, including me, until I wrote this article.

The problem was that a Windows image is captured and also saved into a bitmap file. But, when it is opened with any paint tool, it will be seen as white only and also will not appear properly in the thumbnail view of Windows Explorer. But, after you save this bitmap file, using MS Paint or any other paint tool, it will open properly again as a common bitmap. Here, with this cool code, I have solved this problem. I hope it will be helpful to someone.

I also needed to capture an active window image and to save it into the ".bmp" file format. Therefore, I have written code to capture the window image and to save it into the BMP format.

Here, I used two functions, WndToBmpFile() and DDBToDIB(). Here is cool code for it.

About the Author

Hi! Guys,
I am not a well-experienced programmer but always try to do my best. So, that's why I have found this solution. I am working in an Indian Company as a senior programmer. We develop software and hardware related to video mixing and photography. My desire is to do a lot in the VC++ field especially in Graphics and Image Processing side. This is my beginning, so maybe you will not find many problems with my code. But, your appreciation will become an inspiration for me.

Code Compilation and Testing

I have compiled and tested well this code. So, don't bother about it!!

Shailesh N. Kanzariya,

Function Name :BOOL WndToBmpFile(CDC *pDC, CString szFile)
  CDC *pDC: is pointer to window DC whose image should be
  CString szFile : is null terminated string with that name Bmp
    file should be saved.

//it will capture a wnd image and save it into a bmp file

BOOL WndToBmpFile(CDC *pDC, CString szFile)
//it will capture a wnd image and save it into a bmp file

  CString fname=szFile;
  CBitmap bmp,*pOldBmp;
  CRect rect;
  CWnd *pWnd;
  BOOL flg=0;
  CPalette pal;

  if(pDC==NULL)               //if pDC is NULL return
    return FALSE;

  pWnd=pDC->GetWindow();      //Get Window of PDC

  pWnd->GetClientRect(&rect); //Get dimension of Window

    return FALSE;

  CDC memdc;

  memdc.CreateCompatibleDC(pDC);  //Make Compatible DC for memdc
    //Create Compatible DDB

//The following code will detect whether the BMP uses a Raster
//palette or not.

  if(pDC->GetDeviceCaps(RASTERCAPS) & RC_PALETTE)
    int nSize;
    nSize=sizeof(LOGPALETTE) + sizeof(PALETTEENTRY) * 256;
    pLp=(LOGPALETTE*) new BYTE[nSize];

    delete [] pLp;

//will convert bitmap from DDB to DIB see DDBToDIB()
// See DDBToDIB function for more..

    return FALSE;

//This code writes the BMP file

  CFile m_file;
  if(!m_file.Open(fname,CFile::modeWrite |
    return FALSE;
  int nColors= 1 << lpbi->biBitCount;
  hdr.bfType= ((WORD) ('M' << 8) | 'B');
  hdr.bfSize=sizeof(hdr) + GlobalSize(hDIB);
  hdr.bfOffBits=(DWORD) sizeof(hdr) + nColors * sizeof(RGBQUAD);

//This is the tricky part of the code. It will open the BMP file
//again, but in Binary Mode. Then, it will read the first 14
//bytes from the bitmap file.
//It will change the 11th byte from 11 to 36.
//It will change the 14th byte from 4 to 0 because this is the
//basic requirement for the bitmap format.
//So, it will support all PaintBrush Tools and thumbnail views
//of Windows Explorer.

  CBinFile  m_tempFile;    //CBinFile is derived from CFile
  BYTE dummy=0;//14        //14
  BYTE pBuf[14];           //11
  BOOL fres=m_tempFile.Open(fname,CFile::modeReadWrite |

    return FALSE;

  UINT tt=m_tempFile.Read(pBuf,14);
  pBuf[13]=dummy;//will replace from 04 to 00


  return flg;

//it will capture wnd and save into a bmp file
//End of the code


Function Name :HANDLE DDBToDIB(CBitmap &bitmap,
                               DWORD dwCompression,
                               CPalette *pPal)
  CBitmap &bitmap : Compatible Device Dependent Bitmap
  DWORD dwCompression : Compression format for Bitmap must not be
  BI_BITFIELDS in this case.
  CPalette *pPal : Pointer to Palette. If this is NULL, the
  default system palette will be used.

HANDLE DDBToDIB(CBitmap &bitmap, DWORD dwCompression,
                CPalette *pPal)

  BITMAP              bm;
  DWORD               dwLen;
  HANDLE              hDIB;
  HANDLE              handle;
  HDC                 hDC;
  HPALETTE            hPal;

  ASSERT( bitmap.GetSafeHandle() );

  // The function has no arg for bitfields
  if( dwCompression == BI_BITFIELDS )
    return NULL;

  // If a palette has not been supplied, use default palette
  hPal = (HPALETTE) pPal->GetSafeHandle();
  if (hPal==NULL)
    hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE);

  // Get bitmap information

  // Initialize the bitmap infoheader
  bi.biSize          = sizeof(BITMAPINFOHEADER);
  bi.biWidth         = bm.bmWidth;
  bi.biHeight        = bm.bmHeight;
  bi.biPlanes        = 1;
  bi.biBitCount      = bm.bmPlanes * bm.bmBitsPixel;
    //bm.bmPlanes    * bm.bmBitsPixel;
  bi.biCompression   = dwCompression;
  bi.biSizeImage     = 0;
  bi.biXPelsPerMeter = 0;
  bi.biYPelsPerMeter = 0;
  bi.biClrUsed       = 0;
  bi.biClrImportant  = 0;

  // Compute the size of the infoheader and the color table
  int nColors = (1 << bi.biBitCount);
  if( nColors > 256 )
    nColors = 0;
  dwLen  = bi.biSize + nColors * sizeof(RGBQUAD);

  // We need a device context to get the DIB from
  hDC = ::GetDC(NULL);
  hPal = SelectPalette(hDC,hPal,FALSE);

  // Allocate enough memory to hold bitmap infoheader and
  // color table
  hDIB = GlobalAlloc(GMEM_FIXED,dwLen);

  if (!hDIB){
    return NULL;


  *lpbi = bi;

  // Call GetDIBits with a NULL lpBits param, so the device
  // driver will calculate the biSizeImage field
  GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L,
                 (LPBYTE)NULL, (LPBITMAPINFO)lpbi,

  bi = *lpbi;

  // If the driver did not fill in the biSizeImage field, then
  // compute it
  // Each scan line of the image is aligned on a DWORD (32bit)
  // boundary
  if (bi.biSizeImage == 0){
    bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31)
                        & ~31) / 8) * bi.biHeight;

    // If a compression scheme is used, the result may in fact
    // be larger
    // Increase the size to account for this.
    if (dwCompression != BI_RGB)
      bi.biSizeImage = (bi.biSizeImage * 3) / 2;

  // Realloc the buffer so that it can hold all the bits
  dwLen += bi.biSizeImage;
  if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE))
    hDIB = handle;

    // Reselect the original palette
    return NULL;

  // Get the bitmap bits

  // FINALLY get the DIB
  BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(),
        0L,                        // Start scan line
        (DWORD)bi.biHeight,        // # of scan lines
        (LPBYTE)lpbi               // address for bitmap bits
        + (bi.biSize + nColors * sizeof(RGBQUAD)),
        (LPBITMAPINFO)lpbi,        // address of bitmapinfo
        (DWORD)DIB_RGB_COLORS);    // Use RGB for color table

  if( !bGotBits )

    return NULL;


  return hDIB;

//End of the function


Download Project Source - 128 Kb


  • same program in sdk

    Posted by pajaiswal on 09/05/2007 02:56am

    i need the sane program in SDK.can you help me.

  • Small bug

    Posted by ryu on 11/08/2006 08:42pm

    The code: hdr.bfOffBits=(DWORD) sizeof(hdr) + nColors * sizeof(RGBQUAD);
    doesn't contain the sizeof BITMAPINFO and therefore, the offset bits are wrong.

    I think it should be:
    hdr.bfOffBits=(DWORD) sizeof(hdr) + sizeof(BITMAPINFO) + ((nColors-1) * sizeof(RGBQUAD));

    Btw, this is a great article. Thanks for sharing it with me :)

    Cheers :)

  • Offset

    Posted by wuseltum on 06/29/2006 11:15am

    Thanks for your help - this was the first piece of code that worked for me ;) However I've got one problem: The bmp-file contains a certain displacement, a thin strip of the very right side of my window is displayed on the left in the bmp-file. Has anyone else encountered this problem? Thanks again!

    • Re: Offset

      Posted by wuseltum on 10/24/2006 07:57am

      Cool, that was it! Thanks a lot! :)

    • Re: Offset

      Posted by zhouzhen1 on 10/08/2006 11:14am

      I got the same problem. And I find that the biSize is not included when calculating the header info. Actually it should be like this, hdr.bfOffBits=(DWORD) sizeof(hdr) + lpbi->biSize + nColors * sizeof(RGBQUAD);

  • GlobalFree after call to DDBToDIB

    Posted by jazee on 07/28/2005 01:21pm

    The hDIB should be freed after call to DDBToDIB() otherwise a memory leak occurs. In WndToBmpFile( ) Put GlobalFree( hDIB ); after m_file.Write(lpbi,GlobalSize(hDIB)); m_file.Close();

  • Writing failed in 16 BPP

    Posted by yulaw_hieu on 05/05/2005 12:02am

    I try in 16 BPP mode and the image can't display

    • Fix for 16 bit image

      Posted by jazee on 07/28/2005 01:25pm

      The code has a bug in the offset of pBuf Should be 12 not 13. 
       The fix below will make the output match Photoshop 16 bit BMP. 
       (The only difference is file length is 2 bytes short.) 
       Photoshop and Paint open the output. 
       I used: 
       #define BMPSIZE 48 CFile m_tempFile; 
       //CBinFile is derived from CFile BYTE dummy=0; 
       BYTE pBuf[BMPSIZE];
       BOOL fres=m_tempFile.Open(strFile,CFile::modeReadWrite |CFile::typeBinary); 
       UINT tt=m_tempFile.Read(pBuf,BMPSIZE); 
       pBuf[12]=dummy;/ /will replace from 04 to 00 

  • Code is crashing....

    Posted by SanjeevKumar on 05/04/2004 11:08am

    Code is giving access violation at line
    int nColors= 1 << lpbi->biBitCount;
    Is there any solution for this ?

  • Code is crashing....

    Posted by SanjeevKumar on 05/04/2004 11:07am

    Code is giving access violation at line
    int nColors= 1 << lpbi->biBitCount;
    Is there any solution for this ?

Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • U.S. companies are desperately trying to recruit and hire skilled software engineers and developers, but there's simply not enough quality talent to go around. In response, companies often resort to inferior solutions -- hiring substandard developers and engineers, recruiting talent on a part-time or temporary basis, poaching people from competitors, or burdening an already stressed IT staff for more of their labor. Fortunately, there's a better solution. Read this white paper to learn the business value of …

  • Lenovo recommends Windows 8 Pro. "I dropped my laptop getting out of the taxi." This probably sounds familiar to most IT professionals. If your employees are traveling, you know their devices are in for a rough go. Whether it's a trip to the conference room or a convention out of town, any time equipment leaves a user's desk it is at risk of being put into harm's way. Stay connected at all times, whether at the office or on the go, with agile, durable, and flexible devices like the Lenovo® …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date