Screen Capture to the Clipboard

Home
Back To Tips Page

One of the common questions that I find on the microsoft.public forums is "How do I get a bitmap of a window on the screen?" Well, here's a little subroutine I used extensively in writing Win32 Programming, because I realized that for the number of illustrations I wanted for the book, there was no hope of doing screen captures and then hand-editing just the control I wanted to show. So all my Explorers have a little button somewhere that performs a screen capture of the example window and drops it into the clipboard. I could then paste it into the document, or paste it into an editor and save it as a TIFF or JPEG as well.

To capture a window including the cursor, a more complex approach is required. This is described in an accompanying essay.

Note that I use a base CDC object and use Attach and Detach, instead of using the classes CClientDC and CWindowDC.  I did this because each of these classes creates a specific kind of DC, but there was no one class that could create a DC that was either a client DC or a Window DC.  Rather than introduce convoluted code to handle these cases, I just bound the HDC to a generic CDC.


ToClip.h:


void toClipboard(CWnd * wnd, BOOL FullWnd);

ToClip.cpp


#include "stdafx.h"
#include "toclip.h" 
/****************************************************************
*                                 toClipboard
* Inputs:
*       CWnd * wnd: Window whose contents are to be sent 
*                   to the clipboard
*       BOOL FullWnd: TRUE for entire window, 
*                     FALSE for client area
* Result: void
*       
* Effect: 
*       Copies the contents of the client area or the window
*       to the clipboard in CF_BITMAP format.
*****************************************************************/
 
void toClipboard(CWnd * wnd, BOOL FullWnd)
    {
     CDC dc;
     if(FullWnd)
        { /* full window */
         HDC hdc = ::GetWindowDC(wnd->m_hWnd);
         dc.Attach(hdc);
        } /* full window */
     else
        { /* client area only */
         HDC hdc = ::GetDC(wnd->m_hWnd);
         dc.Attach(hdc);
        } /* client area only */
 
     CDC memDC;
     memDC.CreateCompatibleDC(&dc);
 
     CBitmap bm;
     CRect r;
     if(FullWnd)
        wnd->GetWindowRect(&r);
     else
         wnd->GetClientRect(&r);
 
     CString s;
     wnd->GetWindowText(s);
     CSize sz(r.Width(), r.Height());
     bm.CreateCompatibleBitmap(&dc, sz.cx, sz.cy);
     CBitmap * oldbm = memDC.SelectObject(&bm);
     memDC.BitBlt(0, 0, sz.cx, sz.cy, &dc, 0, 0, SRCCOPY);
 
     wnd->GetParent()->OpenClipboard();
     ::EmptyClipboard();
     ::SetClipboardData(CF_BITMAP, bm.m_hObject);
     CloseClipboard();
 
     memDC.SelectObject(oldbm);
     bm.Detach();  // make sure bitmap not deleted with CBitmap object
                   // read my essay on this technique
     ::ReleaseDC(wnd->m_hWnd, dc.Detach()); // 
    }

Acknowledgements

Special thanks to Lim Bio Liong for pointing out that the CDC destructor does not call ReleaseDC. This bug was the result of converting some pure C code to MFC without my being careful enough.

Also, thanks to Charles Tam for pointing out a typo in the previous bug fix, a missing parameter.

7-Mar-02

Note that as of 7-Mar-02, there is an additional line (marked "New", above), which fixes a bug.

2-Jun-07

The line added 7-Mar-02 was incorrect, and required a first parameter to ::ReleaseDC
  Added an explanation of why I did not use CWindowDC or CClientDC

[Dividing Line Image]

The views expressed in these essays are those of the author, and in no way represent, nor are they endorsed by, Microsoft.

Send mail to newcomer@flounder.com with questions or comments about this web site.
Copyright 1999-2007 FlounderCraft, Ltd.,  All Rights Reserved.
Last modified: May 14, 2011