How to snap an OpenGL client and send it to the clipboard

This article demonstrates how to snap an OpenGL client and send it to ClipBoard.
We suppose your screen configuration is set to true color.
We could send the same buffer in a .bmp file in a few lines too....

// Snap OpenGL client and send it to ClipBoard
// so that you can insert it in your favorite
// image editor, Powerpoint, etc...
// Replace CRenderView by your own CView-derived class
void CRenderView::SnapClient()
{
 BeginWaitCursor();

 // Get client geometry
 CRect rect;
 GetClientRect(&rect);
 CSize size(rect.Width(),rect.Height());
 TRACE("  client zone : (%d;%d)\n",size.cx,size.cy);
 // Lines have to be 32 bytes aligned, suppose 24 bits per pixel
 // I just cropped it
 size.cx -= size.cx % 4;
 TRACE("  final client zone : (%d;%d)\n",size.cx,size.cy);

 // Create a bitmap and select it in the device context
 // Note that this will never be used ;-) but no matter
 CBitmap bitmap;
 CDC *pDC = GetDC();
 CDC MemDC;
 ASSERT(MemDC.CreateCompatibleDC(NULL));
 ASSERT(bitmap.CreateCompatibleBitmap(pDC,size.cx,size.cy));
 MemDC.SelectObject(&bitmap);

 // Alloc pixel bytes
 int NbBytes = 3 * size.cx * size.cy;
 unsigned char *pPixelData = new unsigned char[NbBytes];

 // Copy from OpenGL
 ::glReadPixels(0,0,size.cx,size.cy,GL_RGB,GL_UNSIGNED_BYTE,pPixelData);

 // Fill header
 BITMAPINFOHEADER header;
 header.biWidth = size.cx;
 header.biHeight = size.cy;
 header.biSizeImage = NbBytes;
 header.biSize = 40;
 header.biPlanes = 1;
 header.biBitCount =  3 * 8; // RGB
 header.biCompression = 0;
 header.biXPelsPerMeter = 0;
 header.biYPelsPerMeter = 0;
 header.biClrUsed = 0;
 header.biClrImportant = 0;

 // Generate handle
 HANDLE handle = (HANDLE)::GlobalAlloc (GHND,sizeof(BITMAPINFOHEADER) + NbBytes);
 if(handle != NULL)
 {
  // Lock handle
  char *pData = (char *) ::GlobalLock((HGLOBAL)handle);
  // Copy header and data
  memcpy(pData,&header,sizeof(BITMAPINFOHEADER));
  memcpy(pData+sizeof(BITMAPINFOHEADER),pPixelData,NbBytes);
  // Unlock
  ::GlobalUnlock((HGLOBAL)handle);

  // Push DIB in clipboard
  OpenClipboard();
  EmptyClipboard();
  SetClipboardData(CF_DIB,handle);
  CloseClipboard();
 }

 // Cleanup
 MemDC.DeleteDC();
 bitmap.DeleteObject();
 delete [] pPixelData;

 EndWaitCursor();
}