|
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.
- Add the files PrntScreen.cpp and PrntScreen.h to your project.
- In your application (or dialog class etc.), add the following line:
#include "PrntScreen.h"
- 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();
ScrCap->DoPrntScreen();
delete ScrCap;
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
ConstructorThe 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 :) 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 :(
- 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"
| You must Sign In to use this message board. |
|
| | Msgs 1 to 25 of 56 (Total in Forum: 56) (Refresh) | FirstPrevNext |
|
 |
|
|
Great Job of course....May you help us again?...How to discard mouse movemment on CPrintDialog. This is cause Removemenu & another steps don´t work with your way...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I didn´t fully understand your request, sorry. Is it that you would like to have the mouse cursor at the position where it was before the printer dialog was called? Have i understood right?
Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Albert, ...Sorry for...What I need from your CPrntScreen: 1st->Remove CPrintDialog "move" item menu, 2nd->Lock mouse for CPrintDialog screen movement when left click & move done.
Please, see: http://www.codeguru.com/forum/archive/index.php/t-206643.html
Thanks in advance...
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
I was trying to test some part of the codes, but I faced this linking problem.
Problem: nafxcwd.lib(afxmem.obj) : error LNK2005: "void __cdecl operator delete(void *)" (??3@YAXPAX@Z) already defined in LIBCD.lib(dbgdel.obj)
This problem surfaced when I add in CSize or CDC variables.
How am I supposed to solve this problem?
Thank for your attention.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Output: Dumping objects -> {161} client block at 0x00376EA0, subtype c0, 8 bytes long. a CBitmap object at $00376EA0, 8 bytes long Object dump complete. The program '[4020] PrintDlg.exe: Native' has exited with code 0 (0x0).
I tried to fix that by using:
oldImage->DeleteObject();
but i guess that's not it
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
When I use this class in windows98,the printing is failure.
because the class use the function StretchDIBits to print screen,so I change the program
from
if ((iRasterCaps & RC_STRETCHBLT)==0)
to
if ((iRasterCaps & RC_STRETCHDIB)==0)
The class is very goood,thank you so much!!!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hey, your work is surprisingly simple and correct...congratulations.
Although i haven't deep-scanned the code, i was wondering if thre's a simple way to print only the actual window so that fits the page...any hint?
Thanks, Alberto.
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Alberto,
Thanks for the nice words.
To change the code to always to print "fit to page size" (proportional correct off course), you would need to change the stretching section of the code.
See arround line 375, there should be this code:
// Set magnitude of stretching // (in relation of screen to captured area to page size) scrXY = (double)sizeScreen.cx/(double)sizeScreen.cy; prnXY = (double)sizePrn.cx/(double)sizePrn.cy; if (scrXY>prnXY) { zoomx = ((double)sizeClient.cx/(double)sizeScreen.cx); zoomy = ((double)sizeClient.cy/(double)sizeScreen.cy)*(prnXY/scrXY); } else { zoomx = ((double)sizeClient.cx/(double)sizeScreen.cx)*(scrXY/prnXY); zoomy = ((double)sizeClient.cy/(double)sizeScreen.cy); }
Now change it to
// Set magnitude of stretching // (in relation of captured area to page size) scrXY = (double)sizeClient.cx/(double)sizeClient.cy; prnXY = (double)sizePrn.cx/(double)sizePrn.cy; if (scrXY>prnXY) { zoomx = (double)sizeClient.cx; zoomy = ((double)sizeClient.cy) *(prnXY/scrXY); } else { zoomx = ((double)sizeClient.cx)*(scrXY/prnXY); zoomy = (double)sizeClient.cy; }
and you should get the 'fit to page' printing. For active window, use the 2nd example, like
#include "PrntScreen.h" CPrntScreen * ScrCap; ScrCap = new CPrntScreen(); ScrCap->DoPrntScreen(1,0,true); delete ScrCap; ScrCap = NULL;
And please do not forget to fix that error (memory leak) at line 294, as stated in the below posts!
To do so, change line 294 from
CBitmap *oldImage = new CBitmap,srcImage; to
CBitmap *oldImage = new CBitmap; CBitmap srcImage;
Havn't found time to update the article, will do so soon, thought.
Greetings,
Albert Hermann
-- modified at 13:19 Wednesday 11th January, 2006
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
 |
|
|
Hi, thank for a class.
Function void CPrntScreen::DoPrntScreen(int fArea, int fOrientation, bool bDialog)
Change // CBitmap *oldImage = new CBitmap,srcImage;
To CBitmap *oldImage; CBitmap srcImage;
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
Hello all
Say I have a program - for which I have no source code, and it prints a "report" in this case it is actually a Point-Of-Sale RECEIPT going to either a SERIAL or PARALLEL printer port
I want tyo TRAP, the print Job, before it gets to the port, re-package it (add some Logo, and header / footer lines) and then let go of it to the intended printer..
Can this be done? Any suggestions please (using MFC / C++)
Thanks Alex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
No, don't have no real idea, if this can be made in an easy way. Looks like you would have to programm a device driver to capture the parallel port or something like that.
Sorry that i can´t help.
Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Albert,
Thanks for you code. I have a dialog application that needs printing and your code is perfect for it. You have saved me a lot of time!!!
Cheers Macca
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I saw this article 15 minutes ago. Automatic screen dump to printer is now implemented in my project. Works like a charm. I haven't even read the code yet. Just plugged it in. Talk about useful article. Got an "Excellent" vote from me. The first to receive it in here
One suggestion though, for the sake of user feedback: Encapsulate the DoPrntScreen() call with BeginWaitCursor() and EndWaitCursor(), since the call takes a couple of seconds to return. Especially informative if you use just the default printer.
DP TO THE PEOPLE
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Thanks for the nice comments. Nice to see, that the code helps others, like i was help by a lot of the code here at the Code Project.
Actually, my private version has BeginWaitCursor() and EndWaitCursor() implemented, but i didn´t think that others would like this. It´s really time to update the code and implement the suggestion made here 
Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Albert,
the class works fine!
I have a suggestion: What about making the printer dialog modal?
I've done it this way:
/* PRINTDLG pd */; CPrintDialog pd(FALSE,PD_ALLPAGES,NULL);
All over the Code, this has to be changed:
/* pd.hDC */; pd.GetPrinterDC();
/* pd.hDevMode */; pd.GetDevMode();
And this is the modal call:
//if(PrintDlg(&pd)) if(pd.DoModal()==IDOK)
Best regards Andreas
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Hi Andreas,
Great suggestion (why didn´t i have that idea by myself )
I will test this and add a modal version of the dialog to the article, as soon as i can free up some time (as always too occupied )
Huge thanks
Albert
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
my screen is 1024 x 768. I would like my printing to look exactly like my screen. The text is usually black on white background. the bitmap stretching makes my text blurry. Is there any way to tell the printer that i am sending it a 1024 by 768 image and that it must figure out how to scale it to full paper size so that the text is not blurry.
Just livin a dream.. dont wake me!
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
 |
|
|
I appreciate your help for me. For one week, suffer from this work. Thanks to you, I solved the problem easily, dine out on your code. I'm really Thank You VeryVeryMuch~!^-^
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
Hello
Trying to figure out if my POS Epson receipt printer can print bitmaps or not, using GetDeviceCaps(hDC,RASTERCAPS)on 4 different printers - I get the same result of the returning value = something like 28313
Anything else maybe that I can use?
Cheers Alex
|
| Sign In·View Thread·PermaLink | |
|
|
|
 |
|
|
Alex,
the function GetDeviceCaps(hDC, RASTERCAPS) does actually not test, if the printer can print bitmaps. It returns an information, that can be tested for certain raster capabilities. So you have to check the return value if the desired bit is set. In my code, i was testing specificly the stretchblit capability with
int iRasterCaps=GetDeviceCaps(pd.hDC,RASTERCAPS); if ((iRasterCaps&RC_STRETCHBLT)==0) ... The GetDeviceCaps() function can retrieve diferent device-specific informations, where 'RASTERCAPS' is just one of them.
I think, if you check the TECHNOLOGY feature and then test, if the DT_RASPRINTER bit is set, the printer should be able to print graphics. So maybe you should try something like:
int iDevCaps=GetDeviceCaps(pd.hDC, TECHNOLOGY); if (iDevCaps & DT_RASPRINTER) { ...printer should be able to print graphics }
I am not 100% shure, maybe you will have to play around a bit with this.
Albert
|
| Sign In·View Thread·PermaLink | 2.00/5 (1 vote) |
|
|
|
 |
|
|
General News Question Answer Joke Rant Admin
|