|
The only way how i can imagine how to solve this is to force the dialog back to visible area. Here some code which brings back the dialog to the screen center during capture:
I suppose you use "Dialog Capture", so insert into the following section
case 1:
..
..
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
<-------insert here the code below!
if (nX < 0) nX = 0;
if (nY < 0) nY = 0;
..
..
the following code:
if ((nX < 0)||(nY < 0)||(nX2 > sizeClient.cx) || (nY2 > sizeClient.cy))
{
HWND hwndOwner;
RECT rc, rcDlg, rcOwner;
hwndOwner = GetDesktopWindow();
GetWindowRect(hwndOwner, &rcOwner);
GetWindowRect(wHndle, &rcDlg);
CopyRect(&rc, &rcOwner);
OffsetRect(&rcDlg, -rcDlg.left, -rcDlg.top);
OffsetRect(&rc, -rc.left, -rc.top);
OffsetRect(&rc, -rcDlg.right, -rcDlg.bottom);
SetWindowPos(wHndle,
HWND_TOP,
rcOwner.left + (rc.right / 2),
rcOwner.top + (rc.bottom / 2),
0, 0,
SWP_NOSIZE);
UpdateWindow(wHndle);
GetWindowRect(wHndle,&rectClient);
nX = rectClient.left;
nY = rectClient.top;
nX2 = rectClient.right;
nY2 = rectClient.bottom;
}
Hope that helps,
Albert
|
|
|
|
|
Thanks very much, now my application works correctly!
mais
|
|
|
|
|
When I print the client area in an SDI application I also capture the toolbar, how do I capture the client area without the toolbar?
|
|
|
|
|
The toolbar is part of the client area, so with the this class it is not possible to avoid the capturing of the bar.
It would need a bigger change in the class to implement this, like:
- passing a handle of the toolbar to the DoPrntScreen function (easy)
- retriving the rectangle infos of that window (easy)
- add/subtract point/rectangle coordinates of client and toolbar rectangles, depending orientation of toolbar (tricky)
I can´t look into this for the next 3 months due to project stress, sorry.
Albert
|
|
|
|
|
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);
}
|
|
|
|
|
Dieter,
Interesting idea. I´m heavily occupied with a project atm, but will look into this as soon as possible. Maybe this can resolve the problem, some of the people are getting with the class.
Thanks
Albert
|
|
|
|
|
Yeah, now it works. No more blank sheets!!!!!!!!
|
|
|
|
|
Thanks for the input.
I had exactly the problem you described. I could print on a couple of local printers, but not on the network printers. After implementing your change everything works as described. I can even print on a large plotter.
Thanks again.
|
|
|
|
|
Hello,
I am sorry that it took so long to react. I have checked and tested Dieter Hammer's code now and it works perfectly on all my available printers. So i am preparing a new, updated version and i will upload it as soon as possible. Huge thanks to Dieter!!!!
This new version will include:
- the code suggested by Dieter Hammer, which should eliminate
that nasty blank page problem
- correct printing dialogs, which were partially pushed out of desktop area
- proportional correct printout, independent of paper orientation
- checking, if printer is actually capable for printing image
Albert
|
|
|
|
|
Hello Albert!
I need realy your help! Send me please (if it is possible) a demo project.
mailto: kaiser@nm.ru
|
|
|
|
|
Demo is on the way, check your mail
Albert
|
|
|
|
|
Just returned on Sunday from my vacancy from Europe and just now (was away
for 6 weeks) i had a chance to see the mess i've created with my last
version. I had uploaded an update/bugfix before i started my trip, but
for some reason, Codeproject doesn´t seem to have received it (maybe mail
probs, who knows). Just sent it yesterday again.
The main problem at the last version was, that the memdc doesn´t
combine with the stretch coordinates. This works on some printers, but not
on all. In the new version (uploaded) i calculate the stretching relation at the printer cap side. That version worked on all printers i had access
(laser and deskjets).
If htere is still a problem i will look into Noels suggestion.
Again, big sorry, hope it works now.
|
|
|
|
|
Maybe the printer isn't capable of performing a StretchBlt(...)
Just test this with:
<code>int iRasterCaps=GetDeviceCaps(pDC,RASTERCAPS)
</code>
|
|
|
|
|
Hi everybody !
I implemented your code to make a hardcopy and it worked - for a moment. At homeOffice (HP Deskjet 930C) it worked 10 time very good.
Now beeing in the Office (HP LaserJet 1200) it works only rarely. Most attemps ends with a blank page.
Is there any Problem with device-depindig bmps ? I would like to print an existing memDC (Mirror-Image to make all drawings, when all is finished it will be displayed to the screen to prevent flickering).
But using this DC and calculationg the size etc. causes a blank sheet too. Are there Problems with sizes etc ? It drives me crazy - I have no idea what to do now
Any help ?
Thanks
Martin L
|
|
|
|
|
I have a Lexmark Optra S 1650, plus a couple of other Lexmark printers I've tried printing on, all I can get so far is just the printers to wind up but I don't even get a blank page, I've also tried every possible print option combination. Any ideas?
I have added the changes you mentioned 2 sizeprn lines and changed the stretchBlt line.
Thanks,
Oscar
|
|
|
|
|
Hi, I'm still a beginner in MFC. I was wandering, where to put the command? Do I have to make another button specially for printing or I can use the default?
I'm trying to understand how to print using MFC.
Thx
|
|
|
|
|
Hi there,
I think it's easy. Below you find that part of my source, that will do what you need.
void OPP::OnRButtonDblClk(UINT nFlags, CPoint point)
{
CPrntScreen * ScrCap;
ScrCap = new CPrntScreen();
ScrCap->DoPrntScreen(2,2,FALSE);
delete ScrCap;
ScrCap = NULL;
COlePropertyPage::OnRButtonDblClk(nFlags, point);
}
As you can see, at my programm I i added an Window-Message for
WM_RBUTTONDBLCK which will call the function above.
Hope that helps,
regrads, Rudolf
|
|
|
|
|
First, I like the simplicity of this. Very good.
I created an MFC Dialog application with a command button to execute the print screen. I used the example code given. Actually I tried both. Everything seems to work, but the page printed is blank. Got any ideas what I am doing wrong?
Jeff Brady
CTO Visual Systems, Inc.
|
|
|
|
|
Sorry, my mail doesn´t work atm, so didn´t see this. No, atm i don´t have an idea, will cross check this tomorrow with the src code from the page, just to be sure. I use this code in two commercial projects without prob, but will see.
til later,
Albert
|
|
|
|
|
Jeff,
you are right, there is a bug in the stretching routine
I didn´t see it, because it does not happen on all printers. I had to go through 7 printers for finding 2 which show the same problem you described.
And it only happens, if dialogs are captured, full screen capture (type 0" work perfectly.
Thanks god, that my application are still in developement and the client didn´t see it either
I think, i found the solution and will upload a revised version.
If you need a quickfix, here is how to:
In the printing section, you will find the following 2 lines:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
add there, just before the
pDC->LPtoDP(&sizePrn);
this two lines:
sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
so that you get a:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
pDC->LPtoDP(&sizePrn);
Change the line:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeScreen.cx,sizeScreen.cy,SRCCOPY);
to:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeClient.cx,sizeClient.cy,SRCCOPY);
That should do it!
|
|
|
|
|
Thanks so much!!!
I will test it out later today.
This is my first experience with anyone at CodeProject -- what a breath of fresh air
Jeff
|
|
|
|
|
Albert,
Well I tried the quickfix. Same results.
Old Code:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
pDC->LPtoDP(&sizePrn);
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "CapScreen Printer...";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;
New Code:
sizePrn.cx = pDC->GetDeviceCaps(HORZRES);
sizePrn.cy = pDC->GetDeviceCaps(VERTRES);
sizePrn.cx = (sizePrn.cx*sizeClient.cx)/sizeScreen.cx;
sizePrn.cy = (sizePrn.cy*sizeClient.cy)/sizeScreen.cy;
pDC->LPtoDP(&sizePrn);
di.cbSize = sizeof(DOCINFO);
di.lpszDocName = "CapScreen Printer...";
di.lpszOutput = (LPTSTR) NULL;
di.lpszDatatype = (LPTSTR) NULL;
di.fwType = 0;
My printer is an HP LaserJet 2100 Series PCL6.
Jeff
|
|
|
|
|
Jeff,
if you read the section with the quickfix again, you will see, that there is one more change to make. Maybe you didn´t see it, so here once more:
Change the line:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeScreen.cx,sizeScreen.cy,SRCCOPY);
to:
pDC->StretchBlt(0,0,sizePrn.cx,sizePrn.cy,&memDC,0,0,sizeClient.cx,sizeClient.cy,SRCCOPY);
This change is actually the most important one, because this line caused the problem. Explanation:
sizeScreen holds the screen resulution (full screen)
sizeClient holds the coordinates of the captured area.
I thought, that i can adjust the stretching relation simply there in the StretchBlt function, passing the full screen coordinates as source coordinates. Wrong! This works strangly on some printers, but not on all.
The fix is to adjust the magnification at the destination coordinates (the 2 lines you included) and to use the correct source coordinates (the second change, listed above).
I´ve already uploaded the new code, should be there in a few days.
Sorry again for this inconvenience,
Albert
|
|
|
|
|
Albert,
Tried your code & it works great.
Noticed the emails re: blank pages. I had the same problem until I noticed that my PCL printer (same type as Jeffs) was set to Vector mode instead of Raster mode. After changing to Raster - everything worked fine.
David.
|
|
|
|
|
Albert,
Well I finally got to try the latest code. But.... it still does blank pages.
It is a simple MFC application running under Win2K. The printer is an HP LasetJet 2100 Series PCL 6. The only code I have added is the following triggered by a command button:
void CScreenPrintTestDlg::OnPrintWindow()
{
CPrntScreen * ScrCap;
ScrCap = new CPrntScreen("Impossible to print!","Error!");
ScrCap->DoPrntScreen(1,1,false);
delete ScrCap;
ScrCap = NULL;
}
I am solving my problem with a different solution, but I thought you might want to look at this.
Thanks for your efforts,
Jeff
|
|
|
|
|