Easy Screen Capture with MFC

In an older article published at Codeguru, I showed how easy is to make screen capture using CImage ATL/MFC class. Here is the sample code from that article:

BOOL CScreenImage::CaptureRect(const CRect& rect)
{
   // detach and destroy the old bitmap if any attached
   CImage::Destroy();
   
   // create a screen and a memory device context
   HDC hDCScreen = ::CreateDC(_T("DISPLAY"), NULL, NULL, NULL);
   HDC hDCMem = ::CreateCompatibleDC(hDCScreen);
   // create a compatible bitmap and select it in the memory DC
   HBITMAP hBitmap = 
      ::CreateCompatibleBitmap(hDCScreen, rect.Width(), rect.Height());
   HBITMAP hBmpOld = (HBITMAP)::SelectObject(hDCMem, hBitmap);
 
   // bit-blit from screen to memory device context
   // note: CAPTUREBLT flag is required to capture layered windows
   DWORD dwRop = SRCCOPY | CAPTUREBLT;
   BOOL bRet = ::BitBlt(hDCMem, 0, 0, rect.Width(), rect.Height(), 
                        hDCScreen, rect.left, rect.top, dwRop);
   // attach bitmap handle to this object
   Attach(hBitmap);
 
   // restore the memory DC and perform cleanup
   ::SelectObject(hDCMem, hBmpOld);
   ::DeleteDC(hDCMem);
   ::DeleteDC(hDCScreen);
 
   return bRet;
}

Like a walking in the park. 🙂  However, it can be made even easier, with fewer lines of code.

BOOL CCaptureImage::CaptureRect(const CRect& rcCapture)
{
    // destroy the currently contained bitmap to create a new one
    Destroy();

    // create bitmap and attach it to this object 
    Create(rcCapture.Width(), rcCapture.Height(), 32, 0);

    // create virtual screen DC
    CDC dcScreen;
    dcScreen.CreateDC(_T("DISPLAY"), NULL, NULL, NULL);

    // copy the contents from the virtual screen DC 
    BOOL bRet = ::BitBlt(GetDC(), 0, 0, rcCapture.Width(), rcCapture.Height(),
        dcScreen.m_hDC, rcCapture.left, rcCapture.top,
        SRCCOPY | CAPTUREBLT);

    // do cleanup and return
    dcScreen.DeleteDC();
    ReleaseDC();

    return bRet;
}

Now, let’s add two more methods, one for capturing a given display monitor and one for capture a window.

BOOL CCaptureImage::CaptureDisplayMonitor(const MONITORINFO& monitorInfo)
{
    return CaptureRect(CRect(monitorInfo.rcMonitor));
}

BOOL CCaptureImage::CaptureWindow(CWnd* pWnd)
{
    ASSERT_VALID(pWnd);

    CRect rcWindow;
    pWnd->GetWindowRect(rcWindow);
    return CaptureRect(rcWindow);
}

Demo aplication

Download: Screen Capture Demo.zip (1689 downloads)
The demo application makes per-monitor capture.

Monitor capture demo
Monitor capture demo

 

Resources and related articles

Leave a Comment