home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Tricks of the Windows Gam…ming Gurus (2nd Edition)
/
Disc2.iso
/
msdn_vcb
/
samples
/
vc98
/
sdk
/
com
/
inole2
/
chap01
/
patron
/
print.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
1995-05-03
|
15KB
|
596 lines
/*
* PRINT.CPP
* Patron Chapter 1
*
* Implementation of printing functions for both CPatronDoc
* and CPages classes. These functions are here to keep clutter
* down in document.cpp and pages.cpp.
*
* Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
*
* Kraig Brockschmidt, Microsoft
* Internet : kraigb@microsoft.com
* Compuserve: >INTERNET:kraigb@microsoft.com
*/
#include "patron.h"
static HWND g_hDlgPrint=NULL;
static BOOL g_fCancelPrint=FALSE;
/*
* CPatronDoc::Print
*
* Purpose:
* Prints the current document.
*
* Parameters:
* hWndFrame HWND of the frame to use for dialog parents.
*
* Return Value:
* BOOL TRUE if printing happened, FALSE if it didn't
* start or didn't complete.
*/
BOOL CPatronDoc::Print(HWND hWndFrame)
{
PRINTDLG pd;
BOOL fSuccess;
memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize=sizeof(PRINTDLG);
pd.hwndOwner =hWndFrame;
pd.nCopies =1;
pd.nFromPage =(USHORT)-1;
pd.nToPage =(USHORT)-1;
pd.nMinPage =1;
pd.nMaxPage =m_pPG->NumPagesGet();
pd.lpfnPrintHook=PrintDlgHook;
//Get the current document printer settings
pd.hDevMode=m_pPG->DevModeGet();
pd.Flags=PD_RETURNDC | PD_ALLPAGES | PD_COLLATE
| PD_HIDEPRINTTOFILE | PD_NOSELECTION | PD_ENABLEPRINTHOOK;
if (!PrintDlg(&pd))
return FALSE;
if (NULL!=pd.hDevMode)
GlobalFree(pd.hDevMode);
if (NULL!=pd.hDevNames)
GlobalFree(pd.hDevNames);
//Go do the actual printing.
fSuccess=m_pPG->Print(pd.hDC, PSZ(IDS_DOCUMENTNAME), pd.Flags
, pd.nFromPage, pd.nToPage, pd.nCopies);
if (!fSuccess)
{
MessageBox(m_hWnd, PSZ(IDS_PRINTERROR)
, PSZ(IDS_DOCUMENTCAPTION), MB_OK);
}
return fSuccess;
}
/*
* CPatronDoc::PrinterSetup
*
* Purpose:
* Selects a new printer and options for this document.
*
* Parameters:
* hWndFrame HWND of the frame to use for dialog parents.
* fDefault BOOL to avoid any dialog and just use the
* default.
*
* Return Value:
* UINT Undefined
*/
UINT CPatronDoc::PrinterSetup(HWND hWndFrame, BOOL fDefault)
{
PRINTDLG pd;
//Attempt to get printer metrics for the default printer.
memset(&pd, 0, sizeof(PRINTDLG));
pd.lStructSize=sizeof(PRINTDLG);
if (fDefault)
pd.Flags=PD_RETURNDEFAULT;
else
{
pd.hwndOwner=hWndFrame;
pd.Flags=PD_PRINTSETUP;
//Get the current document printer settings
pd.hDevMode=m_pPG->DevModeGet();
}
if (!PrintDlg(&pd))
return FALSE;
if (!m_pPG->DevModeSet(pd.hDevMode, pd.hDevNames))
{
GlobalFree(pd.hDevNames);
GlobalFree(pd.hDevMode);
return FALSE;
}
FDirtySet(TRUE);
return 1;
}
/*
* PrintDlgHook
*
* Purpose:
* Callback hook for the Print Dialog so we can hide the Setup
* button. Patron only allows Setup before anything exists on
* the page, and is not written to handle setup at Print time.
*/
UINT CALLBACK PrintDlgHook(HWND hDlg, UINT iMsg, WPARAM wParam
, LPARAM lParam)
{
if (WM_INITDIALOG==iMsg)
{
HWND hWnd;
hWnd=GetDlgItem(hDlg, psh1);
ShowWindow(hWnd, SW_HIDE);
return TRUE;
}
return FALSE;
}
/*
* CPages::DevModeSet
*
* Purpose:
* Provides the Pages with the current printer information.
*
* Parameters:
* hDevMode HGLOBAL to the memory containing the DEVMODE.
* This function assumes responsibility for this
* handle.
* hDevNames HGLOBAL providing the driver name and device
* name from which we can create a DC for
* information.
*
* Return Value:
* BOOL TRUE if we could accept this configuration,
* FALSE otherwise. If we return TRUE we also
* delete the old memory we hold.
*/
BOOL CPages::DevModeSet(HGLOBAL hDevMode, HGLOBAL hDevNames)
{
LPDEVNAMES pdn;
LPTSTR psz;
if (NULL==hDevMode || NULL==hDevNames)
return FALSE;
psz=(LPTSTR)GlobalLock(hDevNames);
if (NULL==psz)
return FALSE;
pdn=(LPDEVNAMES)psz;
lstrcpy(m_szDriver, psz+pdn->wDriverOffset);
lstrcpy(m_szDevice, psz+pdn->wDeviceOffset);
lstrcpy(m_szPort, psz+pdn->wOutputOffset);
GlobalUnlock(hDevNames);
GlobalFree(hDevNames);
//Save this new memory and get rid of the old.
if (NULL!=m_hDevMode)
GlobalFree(m_hDevMode);
m_hDevMode=hDevMode;
return ConfigureForDevice();
}
/*
* CPages::DevModeGet
*
* Purpose:
* Retrieves a copy of the current DEVMODE structure for this
* Pages window. The caller is responsible for this memory.
*
* Parameters:
* None
*
* Return Value:
* HGLOBAL Handle to the memory containing the DEVMODE
* structure.
*/
HGLOBAL CPages::DevModeGet(void)
{
HGLOBAL hMem;
DWORD cb;
DWORD i;
LPBYTE pb1, pb2;
cb=GlobalSize(m_hDevMode);
if (0==cb)
return NULL;
hMem=GlobalAlloc(GHND, cb);
if (NULL==hMem)
return NULL;
pb1=(LPBYTE)GlobalLock(hMem);
pb2=(LPBYTE)GlobalLock(m_hDevMode);
//Copy the existing DEVMODE structure
for (i=0; i < cb; i++)
*pb1++=*pb2++;
GlobalUnlock(m_hDevMode);
GlobalUnlock(hMem);
return hMem;
}
/*
* CPages::ConfigureForDevice
*
* Purpose:
* Recalculates our drawing configuration based on the contents of
* an hDC. If no HDC is given we use the contents of our DevMode
* stream.
*
* Parameters:
* None
*
* Return Value:
* BOOL TRUE if successful, FALSE otherwise.
*/
BOOL CPages::ConfigureForDevice(void)
{
POINT ptOffset, ptPaper;
RECT rc;
HDC hDC;
LPDEVMODE pdm;
CHourglass hg; //Shows wait cursor, automatically destroyed
pdm=(LPDEVMODE)GlobalLock(m_hDevMode);
if (NULL==pdm)
return FALSE;
//Get the DC then configure
hDC=CreateIC(m_szDriver, m_szDevice, m_szPort, pdm);
GlobalUnlock(m_hDevMode);
if (NULL==hDC)
return FALSE;
//Get usable page dimensions: already sensitive to orientation
m_cx=GetDeviceCaps(hDC, HORZSIZE)*10-16; //*10: mm to LOMETRIC
m_cy=GetDeviceCaps(hDC, VERTSIZE)*10-16; //-16: for driver bugs.
//Calculate the printer-limited margins on sides in LOMETRIC.
Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, &ptOffset);
Escape(hDC, GETPHYSPAGESIZE, NULL, NULL, &ptPaper);
SetRect(&rc, ptOffset.x, ptOffset.y, ptPaper.x, ptPaper.y);
SetMapMode(hDC, MM_LOMETRIC);
RectConvertMappings(&rc, hDC, FALSE);
//Left and top margins are the printing offset.
m_xMarginLeft= rc.left+8; //+8 to match -16 above
m_yMarginTop =-rc.top+8; //LOMETRIC makes this negative.
//Right is (paper width)-(usable width)-(left margin)
m_xMarginRight =rc.right-m_cx-m_xMarginLeft;
//Bottom is (paper height)-(usable height)-(top margin)+1
m_yMarginBottom=-rc.bottom-m_cy-m_yMarginTop+1;
UpdateScrollRanges();
DeleteDC(hDC);
return TRUE;
}
/*
* CPages::Print
*
* Purpose:
* Prints a specified range of pages to a given hDC. Repeats for
* a given number of copies.
*
* Parameters:
* hDC HDC to which we print.
* pszDoc LPTSTR providing the document name.
* dwFlags DWORD flags from PrintDlg
* iPageStart UINT starting page index (one based)
* iPageEnd UINT ending page index (one based). Includes
* this page.
* cCopies UINT number of copies to print. If PD_COLLATE
* in dwFlags is set, we print multiple copies of
* each page as we cycle through. Otherwise we
* cycle multiple times.
*
* Return Value:
* None
*/
BOOL CPages::Print(HDC hDC, LPTSTR pszDoc, DWORD dwFlags
, UINT iPageStart, UINT iPageEnd, UINT cCopies)
{
BOOL fError=FALSE;
int iPage, iPageInc;
int iUserPage, cPages;
UINT iRepeat, cRepeat;
UINT iCycle, cCycles;
UINT iPageHold=m_iPageCur;
HWND hWndT, hWndTop=NULL;
DOCINFO di;
PCDocument pDoc;
//Validate hDC and page ranges
if (NULL==hDC)
return FALSE;
if ((PD_PAGENUMS & dwFlags))
{
if (-1==iPageStart)
iPageStart=0;
else
iPageStart--; //Switch to zero offset.
if (-1==iPageEnd)
iPageEnd=m_cPages-1;
else
iPageEnd--; //Switch to zero offset.
}
else //Can't test PD_ALLPAGES with & since it's defined as 0L
{
iPageStart=0;
iPageEnd=m_cPages-1;
}
//Arrange cycles and repeats depending on cCopies and collating
if (PD_COLLATE & dwFlags)
{
cCycles=cCopies;
cRepeat=1;
}
else
{
cCycles=1;
cRepeat=cCopies;
}
//Disable the frame window to prevent reentrancy while printing.
hWndT=GetParent(m_hWnd);
pDoc=(PCDocument)SendMessage(hWndT, DOCM_PDOCUMENT, 0, 0L);
if (NULL!=pDoc)
{
PCFrame pFR;
pFR=pDoc->FrameGet();
hWndTop=pFR->Window();
EnableWindow(hWndTop, FALSE);
}
SetAbortProc(hDC, AbortProc);
g_fCancelPrint=FALSE;
//If these don't work then we'll just live without a dialog.
g_hDlgPrint=CreateDialog(m_hInst, MAKEINTRESOURCE(IDD_PRINTING)
, hWndTop, PrintDlgProc);
//Increment for either direction.
iPageInc=(iPageStart > iPageEnd) ? -1 : 1;
//Initial entries in dialog box.
cPages=1+((int)(iPageEnd-iPageStart)*iPageInc);
SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE, 1, (LPARAM)cPages);
SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, 1, (LPARAM)cRepeat);
di.cbSize=sizeof(DOCINFO);
di.lpszDocName=pszDoc;
di.lpszOutput=NULL;
if (StartDoc(hDC, &di) > 0)
{
/*
* Iterate over the pages, repeating each page depending on
* the copies we want and if we have collate enabled.
*/
for (iCycle=1; iCycle <= cCycles; iCycle++)
{
if (PD_COLLATE & dwFlags)
{
SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, iCycle
, (LPARAM)cCycles);
}
//iPageInc controls direction
for (iPage=iPageStart; ; iPage+=iPageInc)
{
iUserPage=1+((iPage-(int)iPageStart)*iPageInc);
SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE
, iUserPage, (LPARAM)cPages);
m_iPageCur=iPage; //We restore this later.
for (iRepeat=1; iRepeat <= cRepeat; iRepeat++)
{
if (!(PD_COLLATE & dwFlags))
{
SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE
, iRepeat, (LPARAM)cRepeat);
}
StartPage(hDC);
Draw(hDC, TRUE, TRUE);
if (EndPage(hDC) < 0)
fError=TRUE;
if (fError || g_fCancelPrint)
break;
}
if (fError || g_fCancelPrint)
break;
//If we just printed the last page, time to quit.
if (iPage==(int)iPageEnd)
break;
}
if (fError || g_fCancelPrint)
break;
}
if (!fError)
EndDoc(hDC);
else
AbortDoc(hDC);
}
else
fError=TRUE;
//Set the page back to what it was before all this started.
m_iPageCur=iPageHold;
EnableWindow(hWndTop, TRUE);
SetFocus(hWndTop);
DestroyWindow(g_hDlgPrint);
DeleteDC(hDC);
return !fError;
}
/*
* AbortProc
*
* Purpose:
* Abort procedure for printing the pages.
*
* Parameters:
* hDC HDC on which printing is happening.
* iErr int error code.
*
* Return Value:
* BOOL TRUE to continue the print job, FALSE otherwise.
*/
BOOL APIENTRY AbortProc(HDC hDC, int iErr)
{
MSG msg;
while (!g_fCancelPrint
&& PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (NULL==g_hDlgPrint
|| !IsDialogMessage(g_hDlgPrint, &msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return !g_fCancelPrint;
}
/*
* PrintDlgProc
*
* Purpose:
* Modeless dialog procedure for the dialog displayed while Patron
* is printing pages.
*/
BOOL APIENTRY PrintDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam
, LPARAM lParam)
{
TCHAR szFormat[40];
TCHAR szOutput[80];
switch (iMsg)
{
case WM_INITDIALOG:
EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE
, MF_GRAYED);
return TRUE;
case WM_COMMAND:
//Cancel button was pressed.
g_fCancelPrint=TRUE;
ShowWindow(hDlg, SW_HIDE);
return TRUE;
case PRINTM_PAGEUPDATE:
GetDlgItemText(hDlg, ID_PAGESTRING, szFormat
, sizeof(szFormat));
wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
SetDlgItemText(hDlg, ID_CURRENTPAGE, szOutput);
return TRUE;
case PRINTM_COPYUPDATE:
GetDlgItemText(hDlg, ID_COPYSTRING, szFormat
, sizeof(szFormat));
wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
SetDlgItemText(hDlg, ID_CURRENTCOPY, szOutput);
return TRUE;
}
return FALSE;
}