Click here to Skip to main content
12,395,871 members (63,223 online)
Click here to Skip to main content
Add your own
alternative version

Stats

135.3K views
3.7K downloads
34 bookmarked
Posted

Easy to use class for ScreenCapture to printer

, 9 May 2004 CPOL
Rate this:
Please Sign up or sign in to vote.
A class for easily capturing screen and printing to default printer.

Introduction

For a project, I'm actually working on, I needed a way to easily create screen shots of the foreground dialog and to print the image directly to the default printer. As I couldn't find the right solution ready for use, I wrote a quick 'n dirty own class, based on the many articles found at The Code Project.

The attached code builds a very easy to use screen capture function, which can be called in a button callback for example. It is possible to adjust the capture area and the print orientation. The desired area will be captured and printed.

Using the code

As said, one of the aims was, to make the class as easy to use as possible.

  1. Add the files PrntScreen.cpp and PrntScreen.h to your project.
  2. In your application (or dialog class etc.), add the following line:
    #include "PrntScreen.h"
  3. At the place, where you want to capture and print the screen, add the following lines to your code:

    Example 1:

    CPrntScreen * ScrCap;
    ScrCap = new CPrntScreen();  //create instance
    ScrCap->DoPrntScreen();  //execute capture function
    delete ScrCap;  //remove instance
    ScrCap=NULL;

    Example2:

    CPrntScreen * ScrCap;
    ScrCap = new CPrntScreen("Some error ocurred!!!","Message");
    ScrCap->DoPrntScreen(1,1,true);
    delete ScrCap;
    ScrCap=NULL;

Example 1 uses just the default parameters, whereas the Example 2 uses available options.

Description

Constructor

The constructor of the class is defined as CPrntScreen(char* sErrTxt, char* sCaption), thus accepting two parameters. The idea was to permit customizing the error message box for your own needs/language.

Description of the parameters:

  • char* sErrTxt = pointer to characters pointing to a desired error message.
  • char* sCaption = pointer to characters pointing to a desired message box caption.
    if the parameters are omitted, the default text/caption will be shown in case of an error.

Functions

The class contains just one function, DoPrntScreen(int nArea, int nOrientation, bool bDialog).
Description of the parameters:

  • nArea determines the area of screen to be captured, with:
    • 0 = Whole screen
    • 1 = Foreground window
    • 2 = Foreground window - Client area
      If parameter is omitted, 0 (Whole Screen) will be used by default

  • nOrientation determines the print orientation, with:
    • 1 = Portrait (you may also use DMORIENT_PORTRAIT)
    • 2 = Landscape (you may also use DMORIENT_LANDSCAPE)
      This parameter is only used, if bDialog=false
      If parameter is omitted, 2 (Portrait) will be used by default

  • bDialog controls, if a printer dialog will be shown:
    • false = Use default printer without showing dialog
    • true = Show printer dialog
      If parameter is omitted, false (Default Printer) will be used by default

History

  • Version 1.0: First version
  • Version 1.1: Updated version.
    Following changes where done:
    • Defined default parameters for even easier use (see example 1 above).
    • Introduced a flag for enabling the use of the printer dialog.
    • Changed the stretching function. Now the captured area will be stretched to printer page in the relation, it has to the whole screen. Capturing of smaller dialogs will not anymore cause huge printouts Smile | :) Having done this, it is definitely best to set print orientation to landscape!
    • The above changes are compatible to the old version, thus no code change is needed when using the new version. Just drop in the new code. Only the printout may change proportions, due to the change of stretching Frown | :(
  • Version 1.1A: Bug fix, fixing an error which caused empty pages on some printers.
  • Version 1.2: Bug fix (hopefully) and new features. This new version includes:
    • The code suggested by Dieter Hammer, which should eliminate that nasty blank page problem
    • Correct printing of dialogs, which were partially pushed out of desktop area
    • Proportional correct printout, independent of paper orientation
    • Checking, if printer is actually capable of printing images
    • And I have added a demo project. The prj file is for VC7, sorry, I don't have VC6 anymore. Just look to the last callback handlers in "PrintDlg.cpp"

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Albert Hermann
Web Developer
Brazil Brazil
IT Programmer since 1987

You may also be interested in...

Comments and Discussions

 
GeneralRe: getdevicecaps Pin
Alex Evans19-Jul-04 16:30
memberAlex Evans19-Jul-04 16:30 
GeneralGreat job - thanks Pin
mvno4-May-04 12:07
membermvno4-May-04 12:07 
GeneralNow I need to print a dialog Pin
mais767-Apr-04 23:16
membermais767-Apr-04 23:16 
GeneralRe: Now I need to print a dialog Pin
Albert Hermann8-Apr-04 10:25
memberAlbert Hermann8-Apr-04 10:25 
GeneralRe: Now I need to print a dialog Pin
mais768-Apr-04 23:37
membermais768-Apr-04 23:37 
GeneralClient area and toolbar Pin
craigsmith00718-Feb-04 16:57
membercraigsmith00718-Feb-04 16:57 
GeneralRe: Client area and toolbar Pin
Albert Hermann2-Mar-04 4:09
memberAlbert Hermann2-Mar-04 4:09 
Generalthis works Pin
Dieter Hammer7-Jan-04 1:33
memberDieter Hammer7-Jan-04 1:33 

I have replace the stretchBlt function by the following code ( took from
http://www.codeproject.com/treectrl/prttview.asp )



The DDBToDIB function is defined at http://www.codeguru.com/bitmap/ddb_to_dib.shtml





void CPrntScreen::DoPrntScreen(int fArea, int fOrientation, bool bDialog)
{
CDC screenDC,memDC;
HDC hscreenDC;
HWND wHndle;
CSize sizeClient, sizeScreen;
RECT rectClient;
POINT pt1, pt2;
int nX, nY, nX2, nY2; // coordinates of rectangle to grab

//determine the area of screen to be captured
//-------------------------------------------
switch (fArea)
{
case 0:
//Capture Whole screen
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
break;

case 1:
//Determine screen size
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);

// Get Foreground window
wHndle=GetForegroundWindow();
hscreenDC = ::GetWindowDC(wHndle);
screenDC.Attach(hscreenDC);

// Calculate resolution of capture area (Window)
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
if (nX2 > sizeClient.cx) nX2 = sizeClient.cx;
if (nY2 > sizeClient.cy) nY2 = sizeClient.cy;
sizeClient.cx = nX2 - nX;
sizeClient.cy = nY2 - nY;
break;

case 2:
//Determine screen size
wHndle=NULL;
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);
sizeScreen.cx = screenDC.GetDeviceCaps(HORZRES);
sizeScreen.cy = screenDC.GetDeviceCaps(VERTRES);
screenDC.DPtoLP(&sizeScreen);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);

// Get Foreground window - Client area
wHndle=GetForegroundWindow();
hscreenDC = ::GetDC(wHndle);
screenDC.Attach(hscreenDC);

// Calculate resolution of capture area (Client)
sizeClient.cx = screenDC.GetDeviceCaps(HORZRES);
sizeClient.cy = screenDC.GetDeviceCaps(VERTRES);
GetClientRect(wHndle,&rectClient);
pt1.x = rectClient.left;
pt1.y = rectClient.top;
pt2.x = rectClient.right;
pt2.y = rectClient.bottom;
ClientToScreen(wHndle,&pt1);
ClientToScreen(wHndle,&pt2);
nX = pt1.x;
nY = pt1.y;
nX2 = pt2.x;
nY2 = pt2.y;
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
if (nX2 > sizeClient.cx) nX2 = sizeClient.cx;
if (nY2 > sizeClient.cy) nY2 = sizeClient.cy;
sizeClient.cx = nX2 - nX;
sizeClient.cy = nY2 - nY;
break;

default:
return;
}

//Screen Capture
CBitmap *oldImage = new CBitmap,srcImage;
memDC.CreateCompatibleDC(&screenDC);
screenDC.DPtoLP(&sizeClient);
srcImage.CreateCompatibleBitmap(&screenDC,sizeClient.cx,sizeClient.cy);
oldImage = memDC.SelectObject(&srcImage);
memDC.PatBlt( 0, 0,sizeClient.cx,sizeClient.cy, WHITENESS);
memDC.BitBlt(0,0,sizeClient.cx,sizeClient.cy,&screenDC,0,0,SRCCOPY);
screenDC.Detach();
ReleaseDC(wHndle,hscreenDC);


// Here starts the printing part
//-------------------------------
PRINTDLG pd;
LPDEVMODE lpDevMode;
CSize sizePrn;
DOCINFO di;
CDC *pDC = new CDC;

memset( &pd, 0, sizeof(PRINTDLG) ) ;

//Fill out PrintDialog structure
pd.lStructSize = sizeof(PRINTDLG);
pd.hDC = NULL;
pd.hwndOwner = NULL;
pd.hInstance = NULL;
pd.nMaxPage = 1;
pd.nMinPage = 1;
pd.nFromPage = 1;
pd.nToPage = 1;
pd.nCopies = 1;
pd.hDevMode = NULL;
pd.hDevNames = NULL;
if (bDialog)
pd.Flags = PD_RETURNDC | PD_USEDEVMODECOPIESANDCOLLATE;
else
pd.Flags = PD_RETURNDC | PD_RETURNDEFAULT;

//Call PrintDialog
if(PrintDlg(&pd))
{
pDC->Attach(pd.hDC);

//If default printer is used, we adjust orientation
if (!bDialog)
{
//Check Orientation
if ((fOrientation!=DMORIENT_LANDSCAPE)&&(fOrientation!=DMORIENT_PORTRAIT))
fOrientation=DMORIENT_PORTRAIT;

// Adjust desired orientation
lpDevMode = (LPDEVMODE)::GlobalLock(pd.hDevMode);
if(lpDevMode != NULL)
{
lpDevMode->dmOrientation=(short)fOrientation;
pDC->ResetDC(lpDevMode);
::GlobalUnlock(pd.hDevMode);
}
}

// Get page dimensions

sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);

pDC->PatBlt( 0, 0, sizePrn.cx, sizePrn.cy, WHITENESS);

// Set magnitude of stretching (in relation screen to captured area)
// sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
// sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;


double zoom = sizePrn.cx / sizeClient.cx;

pDC->LPtoDP(&sizePrn);

// Start printing
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "Lizenzen";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;



::StartDoc(pd.hDC, &di);
::StartPage(pd.hDC);





//pDC->StretchBlt(0,200,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeClient.cx,sizeClient.cy,SRCCOPY);

// Enlarge and print the Bitmap

//copy the bitmap (Device dependant bitmap or DDB)
//to a Device indepedant bitmap (DIB)
CPalette pal;
HANDLE hDIB = DDBToDIB(srcImage, BI_RGB, &pal );
LPBITMAPINFOHEADER lpbi;
lpbi = (LPBITMAPINFOHEADER)hDIB;
int nColors = lpbi->biClrUsed ? lpbi->biClrUsed : 1 << lpbi->biBitCount;
BITMAPINFO &bmInfo = *(LPBITMAPINFO)hDIB;
LPVOID lpDIBBits;
if( bmInfo.bmiHeader.biBitCount > 8 )
lpDIBBits = (LPVOID)((LPDWORD)(bmInfo.bmiColors +
bmInfo.bmiHeader.biClrUsed) +
((bmInfo.bmiHeader.biCompression == BI_BITFIELDS) ? 3 : 0));
else
lpDIBBits = (LPVOID)(bmInfo.bmiColors + nColors);

HDC hDC = pDC->GetSafeHdc();

//copy de DIB to the printer device
//I use DIB rather than DDB because DDB can
//have an unpredicable behavior with network printer !!!!!
StretchDIBits(
hDC, // hDC
0, // DestX
0, // DestY
(int) zoom*sizeClient.cx, // nDestWidth
(int) zoom*sizeClient.cy, // nDestHeight
0, // SrcX
0, // SrcY
sizeClient.cx, // wSrcWidth
sizeClient.cy, // wSrcHeight
lpDIBBits, // lpBits
&bmInfo, // lpBitsInfo
DIB_RGB_COLORS, // wUsage
SRCCOPY); // dwROP






::EndPage(pd.hDC);
::EndDoc(pd.hDC);
}
else if ((!bDialog)||(CommDlgExtendedError()!=0))
MessageBox(NULL,_TEXT(sErrortext),_TEXT(sMsgCaption),MB_OK|MB_ICONERROR);

DeleteDC(pd.hDC);
delete pDC;

memDC.SelectObject(oldImage);

}

GeneralRe: this works Pin
Albert Hermann20-Jan-04 8:33
memberAlbert Hermann20-Jan-04 8:33 
GeneralRe: this works Pin
fauito5-May-04 5:06
sussfauito5-May-04 5:06 
GeneralRe: this works Pin
mvno5-May-04 9:13
membermvno5-May-04 9:13 
GeneralRe: this works Pin
Albert Hermann7-May-04 9:59
memberAlbert Hermann7-May-04 9:59 
QuestionCould you send me a demo project? Pin
K@iser22-Nov-03 11:48
memberK@iser22-Nov-03 11:48 
AnswerRe: Could you send me a demo project? Pin
Albert Hermann24-Nov-03 2:55
memberAlbert Hermann24-Nov-03 2:55 
GeneralBig sorry for the mess Pin
Albert Hermann25-Sep-03 10:39
memberAlbert Hermann25-Sep-03 10:39 
GeneralSmall suggestion Pin
John Noël25-Sep-03 1:18
memberJohn Noël25-Sep-03 1:18 
Generalprinting from time to time Pin
Martin_Leh14-Aug-03 7:09
memberMartin_Leh14-Aug-03 7:09 
GeneralNo luck printing :( Pin
oscar_r6-Aug-03 9:44
memberoscar_r6-Aug-03 9:44 
Generalhmm... Pin
eagertolearn3-Aug-03 6:03
membereagertolearn3-Aug-03 6:03 
GeneralRe: hmm... Pin
MessnerEW18-Feb-04 20:31
memberMessnerEW18-Feb-04 20:31 
Generalworks but prints blank pages Pin
JBrady31-Jul-03 6:49
memberJBrady31-Jul-03 6:49 
GeneralRe: works but prints blank pages Pin
Albert Hermann31-Jul-03 15:21
memberAlbert Hermann31-Jul-03 15:21 
GeneralRe: works but prints blank pages Pin
Albert Hermann1-Aug-03 9:33
memberAlbert Hermann1-Aug-03 9:33 
GeneralRe: works but prints blank pages Pin
JBrady1-Aug-03 10:06
memberJBrady1-Aug-03 10:06 
GeneralRe: works but prints blank pages Pin
JBrady1-Aug-03 11:21
memberJBrady1-Aug-03 11:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.160721.1 | Last Updated 10 May 2004
Article Copyright 2003 by Albert Hermann
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid