HOWTO: Capture and Print an Entire Window

ID: Q186736

The information in this article applies to:

SUMMARY

This article demonstrates one technique for capturing the entire contents of a window (including the non-client area) and printing it to the default printer. To do this, the code creates an intermediate surface that is 24- bits per pixel, copies the contents of the specified window to the intermediate surface, and then stretches the intermediate surface to fill the entire display area in the printer DC.

MORE INFORMATION

Sample Code

   // Return a HDC for the default printer.
   HDC GetPrinterDC(void)
   {
      PRINTDLG pdlg;

      memset( &pdlg, 0, sizeof( PRINTDLG ) );
      pdlg.lStructSize = sizeof( PRINTDLG );
      pdlg.Flags = PD_RETURNDEFAULT | PD_RETURNDC;
      PrintDlg( &pdlg );
      return pdlg.hDC;
   }

   // Create a copy of the current system palette.
   HPALETTE GetSystemPalette()
   {
       HDC hDC;
       HPALETTE hPal;
       HANDLE hLogPal;
       LPLOGPALETTE lpLogPal;

       // Get a DC for the desktop.
       hDC = GetDC(NULL);

       // Check to see if you are a running in a palette-based video mode.
       if (!(GetDeviceCaps(hDC, RASTERCAPS) & RC_PALETTE)) {
           ReleaseDC(NULL, hDC);
           return NULL;
       }

       // Allocate memory for the palette.
       lpLogPal = GlobalAlloc(GPTR, sizeof(LOGPALETTE) + 256 *
                              sizeof(PALETTEENTRY));
       if (!hLogPal)
           return NULL;

       // Initialize.
       lpLogPal->palVersion = 0x300;
       lpLogPal->palNumEntries = 256;

       // Copy the current system palette into the logical palette.
       GetSystemPaletteEntries(hDC, 0, 256,
           (LPPALETTEENTRY)(lpLogPal->palPalEntry));

       // Create the palette.
       hPal = CreatePalette(lpLogPal);

       // Clean up.
       GlobalFree(lpLogPal);
       ReleaseDC(NULL, hDC);

       return hPal;
   }

   // Create a 24-bit-per-pixel surface.
   HBITMAP Create24BPPDIBSection(HDC hDC, int iWidth, int iHeight)
   {
       BITMAPINFO bmi;
       HBITMAP hbm;
       LPBYTE pBits;

       // Initialize to 0s.
       ZeroMemory(&bmi, sizeof(bmi));

       // Initialize the header.
       bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
       bmi.bmiHeader.biWidth = iWidth;
       bmi.bmiHeader.biHeight = iHeight;
       bmi.bmiHeader.biPlanes = 1;
       bmi.bmiHeader.biBitCount = 24;
       bmi.bmiHeader.biCompression = BI_RGB;

       // Create the surface.
       hbm = CreateDIBSection(hDC, &bmi, DIB_RGB_COLORS, &pBits, NULL, 0);

       return(hbm);
   }

   // Print the entire contents (including the non-client area) of
   // the specified window to the default printer.
   BOOL PrintWindowToDC(HWND hWnd)
   {
       HBITMAP hbm;
       HDC     hdcPrinter;
       HDC     hdcMemory;
       HDC     hdcWindow;
       int     iWidth;
       int     iHeight;
       DOCINFO di;
       RECT    rc;
       DIBSECTION ds;
       HPALETTE   hPal;

       // Do you have a valid window?
       if (!IsWindow(hWnd))
           return FALSE;

       // Get a HDC for the default printer.
       hdcPrinter = GetPrinterDC();
       if (!hdcPrinter)
           return FALSE;

       // Get the HDC for the entire window.
       hdcWindow  = GetWindowDC(hWnd);

       // Get the rectangle bounding the window.
       GetWindowRect(hWnd, &rc);

       // Adjust coordinates to client area.
       OffsetRect(&rc, -rc.left, -rc.top);

       // Get the resolution of the printer device.
       iWidth  = GetDeviceCaps(hdcPrinter, HORZRES);
       iHeight = GetDeviceCaps(hdcPrinter, VERTRES);

       // Create the intermediate drawing surface at window resolution.
       hbm = Create24BPPDIBSection(hdcWindow, rc.right, rc.bottom);
       if (!hbm) {
           DeleteDC(hdcPrinter);
           ReleaseDC(hWnd, hdcWindow);
           return FALSE;
       }

       // Prepare the surface for drawing.
       hdcMemory = CreateCompatibleDC(hdcWindow);
       SelectObject(hdcMemory, hbm);

       // Get the current system palette.
       hPal = GetSystemPalette();

       // If a palette was returned.
       if (hPal) {
           // Apply the palette to the source DC.
           SelectPalette(hdcWindow, hPal, FALSE);
           RealizePalette(hdcWindow);

           // Apply the palette to the destination DC.
           SelectPalette(hdcMemory, hPal, FALSE);
           RealizePalette(hdcMemory);
       }

       // Copy the window contents to the memory surface.
       BitBlt(hdcMemory, 0, 0, rc.right, rc.bottom,
           hdcWindow, 0, 0, SRCCOPY);

       // Prepare the DOCINFO.
       ZeroMemory(&di, sizeof(di));
       di.cbSize = sizeof(di);
       di.lpszDocName = "Window Contents";

       // Initialize the print job.
       if (StartDoc(hdcPrinter, &di) > 0) {

           // Prepare to send a page.
           if (StartPage(hdcPrinter) > 0) {

               // Retrieve the information describing the surface.
               GetObject(hbm, sizeof(DIBSECTION), &ds);

               // Print the contents of the surface.
               StretchDIBits(hdcPrinter,
                   0, 0, iWidth, iHeight,
                   0, 0, rc.right, rc.bottom,
                   ds.dsBm.bmBits,
                   (LPBITMAPINFO)&ds.dsBmih,
                   DIB_RGB_COLORS,
                   SRCCOPY);

               // Let the driver know the page is done.
               EndPage(hdcPrinter);
           }

           // Let the driver know the document is done.
           EndDoc(hdcPrinter);
       }

       // Clean up the objects you created.
       DeleteDC(hdcPrinter);
       DeleteDC(hdcMemory);
       ReleaseDC(hWnd, hdcWindow);
       DeleteObject(hbm);
       if (hPal)
           DeleteObject(hPal);
   }

REFERENCES

For more information on capturing images from the screen, see the WINCAP32 sample in the Microsoft Platform SDK.

Additional query words: kbDSupport kbdsd kbGDI kbPrinting kbBitmap kbDisplay

Version           : WINNT:
Platform          : winnt
Issue type        : kbhowto

Last Reviewed: June 2, 1998