|
|
/*
* npprint.c -- Code for printing from notepad. * Copyright (C) 1984-2000 Microsoft Corporation */
#define NOMINMAX
#include "precomp.h"
//#define DBGPRINT
/* indices into chBuff */ #define LEFT 0
#define CENTER 1
#define RIGHT 2
INT tabSize; /* Size of a tab for print device in device units*/ HWND hAbortDlgWnd; INT fAbort; /* true if abort in progress */ INT yPrintChar; /* height of a character */
RECT rtMargin;
/* left,center and right string for header or trailer */ #define MAXTITLE MAX_PATH
TCHAR chBuff[RIGHT+1][MAXTITLE];
/* date and time stuff for headers */ #define MAXDATE MAX_PATH
#define MAXTIME MAX_PATH
TCHAR szFormattedDate[MAXDATE]=TEXT("Y"); // formatted date (may be internationalized)
TCHAR szFormattedTime[MAXTIME]=TEXT("Y"); // formatted time (may be internaltionalized)
SYSTEMTIME PrintTime; // time we started printing
INT xPrintRes; // printer resolution in x direction
INT yPrintRes; // printer resolution in y direction
INT yPixInch; // pixels/inch
INT xPhysRes; // physical resolution x of paper
INT yPhysRes; // physical resolution y of paper
INT xPhysOff; // physical offset x
INT yPhysOff; // physical offset y
INT dyTop; // width of top border (pixels)
INT dyBottom; // width of bottom border
INT dxLeft; // width of left border
INT dxRight; // width of right border
INT iPageNum; // global page number currently being printed
/* define a type for NUM and the base */ typedef long NUM; #define BASE 100L
/* converting in/out of fixed point */ #define NumToShort(x,s) (LOWORD(((x) + (s)) / BASE))
#define NumRemToShort(x) (LOWORD((x) % BASE))
/* rounding options for NumToShort */ #define NUMFLOOR 0
#define NUMROUND (BASE/2)
#define NUMCEILING (BASE-1)
#define ROUND(x) NumToShort(x,NUMROUND)
#define FLOOR(x) NumToShort(x,NUMFLOOR)
/* Unit conversion */ #define InchesToCM(x) (((x) * 254L + 50) / 100)
#define CMToInches(x) (((x) * 100L + 127) / 254)
void DestroyAbortWnd(void) ; VOID TranslateString(TCHAR *);
BOOL CALLBACK AbortProc(HDC hPrintDC, INT reserved) { MSG msg;
while( !fAbort && PeekMessage((LPMSG)&msg, NULL, 0, 0, TRUE) ) { if( !hAbortDlgWnd || !IsDialogMessage( hAbortDlgWnd, (LPMSG)&msg ) ) { TranslateMessage( (LPMSG)&msg ); DispatchMessage( (LPMSG)&msg ); } } return( !fAbort );
UNREFERENCED_PARAMETER(hPrintDC); UNREFERENCED_PARAMETER(reserved); }
INT_PTR CALLBACK AbortDlgProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HMENU hSysMenu;
switch( msg ) { case WM_COMMAND: fAbort= TRUE; DestroyAbortWnd(); return( TRUE );
case WM_INITDIALOG: hSysMenu= GetSystemMenu( hwnd, FALSE ); SetDlgItemText( hwnd, ID_FILENAME, FUntitled() ? szUntitled : PFileInPath(szFileOpened) ); SetFocus( hwnd ); return( TRUE );
case WM_INITMENU: EnableMenuItem( hSysMenu, (WORD)SC_CLOSE, (DWORD)MF_GRAYED ); return( TRUE ); } return( FALSE );
UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(lParam); }
/*
* print out the translated header/footer string in proper position. * uses globals xPrintWidth, ... * * returns 1 if line was printed, otherwise 0. */
INT PrintHeaderFooter (HDC hDC, INT nHF) { SIZE Size; // to compute the width of each string
INT yPos; // y position to print
INT xPos; // x position to print
if( *chPageText[nHF] == 0 ) // see if anything to do
return 0; // we didn't print
TranslateString( chPageText[nHF] );
// figure out the y position we are printing
if( nHF == HEADER ) yPos= dyTop; else yPos= yPrintRes - dyBottom - yPrintChar;
// print out the various strings
// N.B. could overprint which seems ok for now
if( *chBuff[LEFT] ) // left string
{ TextOut( hDC, dxLeft, yPos, chBuff[LEFT], lstrlen(chBuff[LEFT]) ); }
if( *chBuff[CENTER] ) // center string
{ GetTextExtentPoint32( hDC, chBuff[CENTER], lstrlen(chBuff[CENTER]), &Size ); xPos= (xPrintRes-dxRight+dxLeft)/2 - Size.cx/2; TextOut( hDC, xPos, yPos, chBuff[CENTER], lstrlen(chBuff[CENTER]) ); }
if( *chBuff[RIGHT] ) // right string
{ GetTextExtentPoint32( hDC, chBuff[RIGHT], lstrlen(chBuff[RIGHT]), &Size ); xPos= xPrintRes - dxRight - Size.cx; TextOut( hDC, xPos, yPos, chBuff[RIGHT], lstrlen(chBuff[RIGHT]) ); } return 1; // we did print something
} /*
* GetResolutions * * Gets printer resolutions. * sets globals: xPrintRes, yPrintRes, yPixInch * */
VOID GetResolutions(HDC hPrintDC) { xPrintRes = GetDeviceCaps( hPrintDC, HORZRES ); yPrintRes = GetDeviceCaps( hPrintDC, VERTRES ); yPixInch = GetDeviceCaps( hPrintDC, LOGPIXELSY );
xPhysRes = GetDeviceCaps( hPrintDC, PHYSICALWIDTH ); yPhysRes = GetDeviceCaps( hPrintDC, PHYSICALHEIGHT );
xPhysOff = GetDeviceCaps( hPrintDC, PHYSICALOFFSETX ); yPhysOff = GetDeviceCaps( hPrintDC, PHYSICALOFFSETY ); }
/* GetMoreText
* * Gets the next line of text from the MLE, returning a pointer * to the beginning and just past the end. * * linenum - index into MLE (IN) * pStartText - start of MLE (IN) * ppsStr - pointer to where to put pointer to start of text (OUT) * ppEOL - pointer to where to put pointer to just past EOL (OUT) * */
VOID GetMoreText( INT linenum, PTCHAR pStartText, PTCHAR* ppsStr, PTCHAR* ppEOL ) { INT Offset; // offset in 'chars' into edit buffer
INT nChars; // number of chars in line
Offset= (INT)SendMessage( hwndEdit, EM_LINEINDEX, linenum, 0 );
nChars= (INT)SendMessage( hwndEdit, EM_LINELENGTH, Offset, 0 );
*ppsStr= pStartText + Offset;
*ppEOL= (pStartText+Offset) + nChars; }
#ifdef DBGPRINT
TCHAR dbuf[100]; VOID ShowMargins( HDC hPrintDC ) { INT xPrintRes, yPrintRes; RECT rct; HBRUSH hBrush;
xPrintRes= GetDeviceCaps( hPrintDC, HORZRES ); yPrintRes= GetDeviceCaps( hPrintDC, VERTRES ); hBrush= GetStockObject( BLACK_BRUSH );
if ( hBrush ) { SetRect( &rct, 0,0,xPrintRes-1, yPrintRes-1 ); FrameRect( hPrintDC, &rct, hBrush ); SetRect( &rct, dxLeft, dyTop, xPrintRes-dxRight, yPrintRes-dyBottom ); FrameRect( hPrintDC, &rct, hBrush ); } }
VOID PrintLogFont( LOGFONT lf ) { wsprintf(dbuf,TEXT("lfHeight %d\n"), lf.lfHeight ); ODS(dbuf); wsprintf(dbuf,TEXT("lfWidth %d\n"), lf.lfWidth ); ODS(dbuf); wsprintf(dbuf,TEXT("lfEscapement %d\n"), lf. lfEscapement ); ODS(dbuf); wsprintf(dbuf,TEXT("lfOrientation %d\n"), lf.lfOrientation ); ODS(dbuf); wsprintf(dbuf,TEXT("lfWeight %d\n"), lf.lfWeight ); ODS(dbuf); wsprintf(dbuf,TEXT("lfItalic %d\n"), lf.lfItalic ); ODS(dbuf); wsprintf(dbuf,TEXT("lfUnderline %d\n"), lf.lfUnderline ); ODS(dbuf); wsprintf(dbuf,TEXT("lfStrikeOut %d\n"), lf.lfStrikeOut ); ODS(dbuf); wsprintf(dbuf,TEXT("lfCharSet %d\n"), lf.lfCharSet ); ODS(dbuf); wsprintf(dbuf,TEXT("lfOutPrecision %d\n"), lf.lfOutPrecision ); ODS(dbuf); wsprintf(dbuf,TEXT("lfClipPrecison %d\n"), lf.lfClipPrecision ); ODS(dbuf); wsprintf(dbuf,TEXT("lfQuality %d\n"), lf.lfQuality ); ODS(dbuf); wsprintf(dbuf,TEXT("lfPitchAndFamily %d\n"), lf.lfPitchAndFamily); ODS(dbuf); wsprintf(dbuf,TEXT("lfFaceName %s\n"), lf.lfFaceName ); ODS(dbuf); } #endif
// GetPrinterDCviaDialog
//
// Use the common dialog PrintDlgEx() function to get a printer DC to print to.
//
// Returns: valid HDC or INVALID_HANDLE_VALUE if error.
//
HDC GetPrinterDCviaDialog( VOID ) { PRINTDLGEX pdTemp; HDC hDC; HRESULT hRes;
//
// Get the page setup information
//
if( !g_PageSetupDlg.hDevNames ) /* Retrieve default printer if none selected. */ { g_PageSetupDlg.Flags |= (PSD_RETURNDEFAULT|PSD_NOWARNING ); PageSetupDlg(&g_PageSetupDlg); g_PageSetupDlg.Flags &= ~(PSD_RETURNDEFAULT|PSD_NOWARNING); }
//
// Initialize the dialog structure
//
ZeroMemory( &pdTemp, sizeof(pdTemp) );
pdTemp.lStructSize= sizeof(pdTemp);
pdTemp.hwndOwner= hwndNP; pdTemp.nStartPage= START_PAGE_GENERAL; pdTemp.Flags= PD_NOPAGENUMS | PD_RETURNDC | PD_NOCURRENTPAGE | PD_NOSELECTION | 0;
// if use set printer in PageSetup, use it here too.
if( g_PageSetupDlg.hDevMode ) { pdTemp.hDevMode= g_PageSetupDlg.hDevMode; }
if( g_PageSetupDlg.hDevNames ) { pdTemp.hDevNames= g_PageSetupDlg.hDevNames; }
//
// let user select printer
//
hRes= PrintDlgEx( &pdTemp );
//
// get DC if valid return
//
hDC= INVALID_HANDLE_VALUE;
if( hRes == S_OK ) { if( (pdTemp.dwResultAction == PD_RESULT_PRINT) || (pdTemp.dwResultAction == PD_RESULT_APPLY) ) { if( pdTemp.dwResultAction == PD_RESULT_PRINT ) { hDC= pdTemp.hDC; } //
// Get the page setup information for the printer selected in case it was
// the first printer added by the user through notepad.
//
if( !g_PageSetupDlg.hDevMode ) { g_PageSetupDlg.Flags |= (PSD_RETURNDEFAULT|PSD_NOWARNING ); PageSetupDlg(&g_PageSetupDlg); g_PageSetupDlg.Flags &= ~(PSD_RETURNDEFAULT|PSD_NOWARNING); }
// change devmode if user pressed print or apply
g_PageSetupDlg.hDevMode= pdTemp.hDevMode; g_PageSetupDlg.hDevNames= pdTemp.hDevNames; } }
// FEATURE: free hDevNames
return( hDC ); }
INT NpPrint( PRINT_DIALOG_TYPE type) { HDC hPrintDC;
SetCursor( hWaitCursor );
switch( type ) { case UseDialog: hPrintDC= GetPrinterDCviaDialog(); break; case NoDialogNonDefault: hPrintDC= GetNonDefPrinterDC(); break; case DoNotUseDialog: default: hPrintDC= GetPrinterDC(); break; }
if( hPrintDC == INVALID_HANDLE_VALUE ) { SetCursor( hStdCursor ); return( 0 ); // message already given
}
return( NpPrintGivenDC( hPrintDC ) );
}
INT NpPrintGivenDC( HDC hPrintDC ) { HANDLE hText= NULL; // handle to MLE text
HFONT hPrintFont= NULL; // font to print with
HANDLE hPrevFont= NULL; // previous font in hPrintDC
BOOL fPageStarted= FALSE; // true if StartPage called for this page
BOOL fDocStarted= FALSE; // true if StartDoc called
PTCHAR pStartText= NULL; // start of edit text (locked hText)
TEXTMETRIC Metrics; TCHAR msgbuf[MAX_PATH]; // Document name for tracking print job
INT nLinesPerPage; // not inc. header and footer
// iErr will contain the first error discovered ie it is sticky
// This will be the value returned by this function.
// It does not need to translate SP_* errors except for SP_ERROR which should be
// GetLastError() right after it is first detected.
INT iErr=0; // error return
DOCINFO DocInfo; LOGFONT lfPrintFont; // local version of FontStruct
LCID lcid; // locale id
fAbort = FALSE; hAbortDlgWnd= NULL;
SetCursor( hWaitCursor );
GetResolutions( hPrintDC );
// Get the time and date for use in the header or trailer.
// We use the GetDateFormat and GetTimeFormat to get the
// internationalized versions.
GetLocalTime( &PrintTime ); // use local, not gmt
lcid= GetUserDefaultLCID();
GetDateFormat( lcid, DATE_LONGDATE, &PrintTime, NULL, szFormattedDate, MAXDATE );
GetTimeFormat( lcid, 0, &PrintTime, NULL, szFormattedTime, MAXTIME );
/*
* This part is to select the current font to the printer device. * We have to change the height because FontStruct was created * assuming the display. Using the remembered pointsize, calculate * the new height. */
lfPrintFont= FontStruct; // make local copy
lfPrintFont.lfHeight= -(iPointSize*yPixInch)/(72*10); lfPrintFont.lfWidth= 0;
//
// convert margins to pixels
// ptPaperSize is the physical paper size, not the printable area.
// do the mapping in physical units
//
SetMapMode( hPrintDC, MM_ANISOTROPIC );
SetViewportExtEx( hPrintDC, xPhysRes, yPhysRes, NULL );
SetWindowExtEx( hPrintDC, g_PageSetupDlg.ptPaperSize.x, g_PageSetupDlg.ptPaperSize.y, NULL );
rtMargin = g_PageSetupDlg.rtMargin;
LPtoDP( hPrintDC, (LPPOINT) &rtMargin, 2 );
SetMapMode( hPrintDC,MM_TEXT ); // restore to mm_text mode
hPrintFont= CreateFontIndirect(&lfPrintFont);
if( !hPrintFont ) { goto ErrorExit; }
hPrevFont= SelectObject( hPrintDC, hPrintFont ); if( !hPrevFont ) { goto ErrorExit; }
SetBkMode( hPrintDC, TRANSPARENT ); if( !GetTextMetrics( hPrintDC, (LPTEXTMETRIC) &Metrics ) ) { goto ErrorExit; }
// The font may not a scalable (say on a bubblejet printer)
// In this case, just pick some font
// For example, FixedSys 9 pt would be non-scalable
if( !(Metrics.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE )) ) { // remove just created font
hPrintFont= SelectObject( hPrintDC, hPrevFont ); // get old font
DeleteObject( hPrintFont );
memset( lfPrintFont.lfFaceName, 0, LF_FACESIZE*sizeof(TCHAR) );
hPrintFont= CreateFontIndirect( &lfPrintFont ); if( !hPrintFont ) { goto ErrorExit; }
hPrevFont= SelectObject( hPrintDC, hPrintFont ); if( !hPrevFont ) { goto ErrorExit; }
if( !GetTextMetrics( hPrintDC, (LPTEXTMETRIC) &Metrics ) ) { goto ErrorExit; } } yPrintChar= Metrics.tmHeight+Metrics.tmExternalLeading; /* the height */
tabSize = Metrics.tmAveCharWidth * 8; /* 8 ave char width pixels for tabs */
// compute margins in pixels
dxLeft= max(rtMargin.left - xPhysOff,0); dxRight= max(rtMargin.right - (xPhysRes - xPrintRes - xPhysOff), 0 ); dyTop= max(rtMargin.top - yPhysOff,0); dyBottom= max(rtMargin.bottom - (yPhysRes - yPrintRes - yPhysOff), 0 );
#ifdef DBGPRINT
{ TCHAR dbuf[100]; RECT rt= g_PageSetupDlg.rtMargin; POINT pt;
wsprintf(dbuf,TEXT("Print pOffx %d pOffy %d\n"), GetDeviceCaps(hPrintDC, PHYSICALOFFSETX), GetDeviceCaps(hPrintDC, PHYSICALOFFSETY)); ODS(dbuf); wsprintf(dbuf,TEXT("PHYSICALWIDTH: %d\n"), xPhysRes); ODS(dbuf); wsprintf(dbuf,TEXT("HORZRES: %d\n"),xPrintRes); ODS(dbuf); wsprintf(dbuf,TEXT("PHYSICALOFFSETX: %d\n"),xPhysOff); ODS(dbuf); wsprintf(dbuf,TEXT("LOGPIXELSX: %d\n"), GetDeviceCaps(hPrintDC,LOGPIXELSX)); ODS(dbuf);
GetViewportOrgEx( hPrintDC, (LPPOINT) &pt ); wsprintf(dbuf,TEXT("Viewport org: %d %d\n"), pt.x, pt.y ); ODS(dbuf); GetWindowOrgEx( hPrintDC, (LPPOINT) &pt ); wsprintf(dbuf,TEXT("Window org: %d %d\n"), pt.x, pt.y ); ODS(dbuf); wsprintf(dbuf,TEXT("PrintRes x: %d y: %d\n"),xPrintRes, yPrintRes); ODS(dbuf); wsprintf(dbuf,TEXT("PaperSize x: %d y: %d\n"), g_PageSetupDlg.ptPaperSize.x, g_PageSetupDlg.ptPaperSize.y ); ODS(dbuf); wsprintf(dbuf,TEXT("unit margins: l: %d r: %d t: %d b: %d\n"), rt.left, rt.right, rt.top, rt.bottom); ODS(dbuf); wsprintf(dbuf,TEXT("pixel margins: l: %d r: %d t: %d b: %d\n"), rtMargin.left, rtMargin.right, rtMargin.top, rtMargin.bottom); ODS(dbuf);
wsprintf(dbuf,TEXT("dxLeft %d dxRight %d\n"),dxLeft,dxRight); ODS(dbuf); wsprintf(dbuf,TEXT("dyTop %d dyBot %d\n"),dyTop,dyBottom); ODS(dbuf); } #endif
/* Number of lines on a page with margins */ /* two lines are used by header and footer */ nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
if( *chPageText[HEADER] ) nLinesPerPage--; if( *chPageText[FOOTER] ) nLinesPerPage--;
/*
** There was a bug in NT once where a printer driver would ** return a font that was larger than the page size which ** would then cause Notepad to constantly print blank pages ** To keep from doing this we check to see if we can fit ANYTHING ** on a page, if not then there is a problem so quit. MarkRi 8/92 */ if( nLinesPerPage <= 0 ) { FontTooBig: MessageBox( hwndNP, szFontTooBig, szNN, MB_APPLMODAL | MB_OK | MB_ICONWARNING );
SetLastError(0); // no error
ErrorExit: iErr= GetLastError(); // remember the first error
ExitWithThisError: // preserve iErr (return SP_* errors)
if( hPrevFont ) { SelectObject( hPrintDC, hPrevFont ); DeleteObject( hPrintFont ); }
if( pStartText ) // were able to lock hText
LocalUnlock( hText );
if( fPageStarted ) { if( EndPage( hPrintDC ) <= 0 ) { // if iErr not already set then set it to the new error code.
if( iErr == 0 ) { iErr= GetLastError(); } } }
if( fDocStarted ) { if( fAbort ) { AbortDoc( hPrintDC ); } else { if( EndDoc( hPrintDC ) <= 0 ) { // if iErr not already set then set it to the new error code.
if (iErr == 0) { iErr= GetLastError(); } } } }
DeleteDC( hPrintDC );
DestroyAbortWnd();
SetCursor( hStdCursor );
if (!fAbort) { return( iErr ); } else { return( SP_USERABORT ); } }
if( (iErr= SetAbortProc (hPrintDC, AbortProc)) < 0 ) { goto ExitWithThisError; }
// get printer to MLE text
hText= (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 0, 0 ); if( !hText ) { goto ErrorExit; } pStartText= LocalLock( hText ); if( !pStartText ) { goto ErrorExit; }
GetWindowText( hwndNP, msgbuf, CharSizeOf(msgbuf) );
EnableWindow( hwndNP, FALSE ); // Disable window to prevent reentrancy
hAbortDlgWnd= CreateDialog( hInstanceNP, (LPTSTR) MAKEINTRESOURCE(IDD_ABORTPRINT), hwndNP, AbortDlgProc);
if( !hAbortDlgWnd ) { goto ErrorExit; }
DocInfo.cbSize= sizeof(DOCINFO); DocInfo.lpszDocName= msgbuf; DocInfo.lpszOutput= NULL; DocInfo.lpszDatatype= NULL; // Type of data used to record print job
DocInfo.fwType= 0; // not DI_APPBANDING
SetLastError(0); // clear error so it reflects errors in the future
if( StartDoc( hPrintDC, &DocInfo ) <= 0 ) { iErr = GetLastError(); goto ExitWithThisError; } fDocStarted= TRUE;
// Basicly, this is just a loop surrounding the DrawTextEx API.
// We have to calculate the printable area which will not include
// the header and footer area.
{ INT iTextLeft; // amount of text left to print
INT iSta; // status
UINT dwDTFormat; // drawtext flags
DRAWTEXTPARAMS dtParm; // drawtext control
RECT rect; // rectangle to draw in
UINT dwDTRigh = 0; // drawtext flags (RTL)
iPageNum= 1; fPageStarted= FALSE;
// calculate the size of the printable area for the text
// not including the header and footer
ZeroMemory( &rect, sizeof(rect) );
rect.left= dxLeft; rect.right= xPrintRes-dxRight; rect.top= dyTop; rect.bottom= yPrintRes-dyBottom;
if( *chPageText[HEADER] != 0 ) { rect.top += yPrintChar; }
if( *chPageText[FOOTER] != 0 ) { rect.bottom -= yPrintChar; }
iTextLeft= lstrlen(pStartText);
//Get the edit control direction.
if (GetWindowLong(hwndEdit, GWL_EXSTYLE) & WS_EX_RTLREADING) dwDTRigh = DT_RIGHT | DT_RTLREADING;
while( !fAbort && (iTextLeft>0) ) { #define MAXSTATUS 100
TCHAR szPagePrinting[MAXSTATUS+1];
// update abort dialog box to inform user where we are in the printing
_sntprintf( szPagePrinting, MAXSTATUS, szCurrentPage, iPageNum ); SetDlgItemText( hAbortDlgWnd, ID_PAGENUMBER, szPagePrinting );
PrintHeaderFooter( hPrintDC, HEADER );
ZeroMemory( &dtParm, sizeof(dtParm) );
dtParm.cbSize= sizeof(dtParm); dtParm.iTabLength= tabSize;
dwDTFormat= DT_EDITCONTROL | DT_LEFT | DT_EXPANDTABS | DT_NOPREFIX | DT_WORDBREAK | dwDTRigh | 0;
if( StartPage( hPrintDC ) <= 0 ) { iErr= GetLastError(); goto ExitWithThisError; } fPageStarted= TRUE;
#ifdef DBGPRINT
ShowMargins(hPrintDC); #endif
/* Ignore errors in printing. EndPage or StartPage will find them */ iSta= DrawTextEx( hPrintDC, pStartText, iTextLeft, &rect, dwDTFormat, &dtParm);
PrintHeaderFooter( hPrintDC, FOOTER );
if( EndPage( hPrintDC ) <= 0 ) { iErr= GetLastError(); goto ExitWithThisError; } fPageStarted= FALSE;
iPageNum++;
// if we can't print a single character (too big perhaps)
// just bail now.
if( dtParm.uiLengthDrawn == 0 ) { goto FontTooBig; }
pStartText += dtParm.uiLengthDrawn; iTextLeft -= dtParm.uiLengthDrawn;
}
}
iErr=0; // no errors
goto ExitWithThisError;
}
VOID DestroyAbortWnd (void) { EnableWindow(hwndNP, TRUE); DestroyWindow(hAbortDlgWnd); hAbortDlgWnd = NULL; }
const DWORD s_PageSetupHelpIDs[] = { ID_HEADER_LABEL, IDH_PAGE_HEADER, ID_HEADER, IDH_PAGE_HEADER, ID_FOOTER_LABEL, IDH_PAGE_FOOTER, ID_FOOTER, IDH_PAGE_FOOTER, 0, 0 };
/*******************************************************************************
* * PageSetupHookProc * * DESCRIPTION: * Callback procedure for the PageSetup common dialog box. * * PARAMETERS: * hWnd, handle of PageSetup window. * Message, * wParam, * lParam, * (returns), * *******************************************************************************/
UINT_PTR CALLBACK PageSetupHookProc( HWND hWnd, UINT Message, WPARAM wParam, LPARAM lParam ) {
INT id; /* ID of dialog edit controls */ POINT pt;
switch (Message) {
case WM_INITDIALOG: for (id = ID_HEADER; id <= ID_FOOTER; id++) { SendDlgItemMessage(hWnd, id, EM_LIMITTEXT, PT_LEN-1, 0L); SetDlgItemText(hWnd, id, chPageText[id - ID_HEADER]); }
SendDlgItemMessage(hWnd, ID_HEADER, EM_SETSEL, 0, MAKELONG(0, PT_LEN-1)); return TRUE;
case WM_DESTROY: // We don't know if the user hit OK or Cancel, so we don't
// want to replace our real copies until we know! We _should_ get
// a notification from the common dialog code!
for( id = ID_HEADER; id <= ID_FOOTER; id++ ) { GetDlgItemText(hWnd, id, chPageTextTemp[id - ID_HEADER],PT_LEN); } break;
case WM_HELP: //
// We only want to intercept help messages for controls that we are
// responsible for.
//
id = GetDlgCtrlID(((LPHELPINFO) lParam)-> hItemHandle);
if (id < ID_HEADER || id > ID_FOOTER_LABEL) break;
WinHelp(((LPHELPINFO) lParam)-> hItemHandle, szHelpFile, HELP_WM_HELP, (UINT_PTR) (LPVOID) s_PageSetupHelpIDs); return TRUE;
case WM_CONTEXTMENU: //
// If the user clicks on any of our labels, then the wParam will
// be the hwnd of the dialog, not the static control. WinHelp()
// handles this, but because we hook the dialog, we must catch it
// first.
//
if( hWnd == (HWND) wParam ) {
GetCursorPos(&pt); ScreenToClient(hWnd, &pt); wParam = (WPARAM) ChildWindowFromPoint(hWnd, pt);
}
//
// We only want to intercept help messages for controls that we are
// responsible for.
//
id = GetDlgCtrlID((HWND) wParam);
if (id < ID_HEADER || id > ID_FOOTER_LABEL) break;
WinHelp((HWND) wParam, szHelpFile, HELP_CONTEXTMENU, (UINT_PTR) (LPVOID) s_PageSetupHelpIDs); return TRUE;
}
return FALSE;
}
/***************************************************************************
* VOID TranslateString(TCHAR *src) * * purpose: * translate a header/footer strings * * supports the following: * * && insert a & char * &f current file name or (untitled) * &d date in Day Month Year * &t time * &p page number * &p+num set first page number to num * * Alignment: * &l, &c, &r for left, center, right * * params: * IN/OUT src this is the string to translate * * * used by: * Header Footer stuff * * uses: * lots of c lib stuff * ***************************************************************************/
VOID TranslateString (TCHAR * src) { // File, Page, Time, Date, Center, Right, Left
// these *never* change so don't put into resources for localizers
TCHAR letters[15]=TEXT("fFpPtTdDcCrRlL"); TCHAR buf[MAX_PATH]; INT page; INT nAlign=CENTER; // current string to add chars to
INT nIndex[RIGHT+1]; // current lengths of (left,center,right)
struct tm *newtime; time_t long_time; INT iLen; // length of strings
nIndex[LEFT] = 0; nIndex[CENTER] = 0; nIndex[RIGHT] = 0;
/* Get the time we need in case we use &t. */ time (&long_time); newtime = localtime (&long_time);
while (*src) /* look at all of source */ { while (*src && *src != TEXT('&')) { chBuff[nAlign][nIndex[nAlign]] = *src++; nIndex[nAlign] += 1; }
if (*src == TEXT('&')) /* is it the escape char? */ { src++;
if (*src == letters[0] || *src == letters[1]) { /* &f file name (no path) */ if (!FUntitled()) { GetFileTitle(szFileOpened, buf, CharSizeOf(buf)); } else { lstrcpy(buf, szUntitled); }
/* Copy to the currently aligned string. */ if( nIndex[nAlign] + lstrlen(buf) < MAXTITLE ) { lstrcpy( chBuff[nAlign] + nIndex[nAlign], buf );
/* Update insertion position. */ nIndex[nAlign] += lstrlen (buf); }
} else if (*src == letters[2] || *src == letters[3]) /* &P or &P+num page */ { src++; page = 0; if (*src == TEXT('+')) /* &p+num case */ { src++; while (_istdigit(*src)) { /* Convert to int on-the-fly*/ page = (10*page) + (*src) - TEXT('0'); src++; } }
wsprintf( buf, TEXT("%d"), iPageNum+page ); // convert to chars
if( nIndex[nAlign] + lstrlen(buf) < MAXTITLE ) { lstrcpy( chBuff[nAlign] + nIndex[nAlign], buf ); nIndex[nAlign] += lstrlen (buf); } src--; } else if (*src == letters[4] || *src == letters[5]) /* &t time */ { iLen= lstrlen( szFormattedTime );
/* extract time */ if( nIndex[nAlign] + iLen < MAXTITLE ) { _tcsncpy (chBuff[nAlign] + nIndex[nAlign], szFormattedTime, iLen); nIndex[nAlign] += iLen; } } else if (*src == letters[6] || *src == letters[7]) /* &d date */ { iLen= lstrlen( szFormattedDate );
/* extract day month day */ if( nIndex[nAlign] + iLen < MAXTITLE ) { _tcsncpy (chBuff[nAlign] + nIndex[nAlign], szFormattedDate, iLen); nIndex[nAlign] += iLen; } } else if (*src == TEXT('&')) /* quote a single & */ { if( nIndex[nAlign] + 1 < MAXTITLE ) { chBuff[nAlign][nIndex[nAlign]] = TEXT('&'); nIndex[nAlign] += 1; } } /* Set the alignment for whichever has last occured. */ else if (*src == letters[8] || *src == letters[9]) /* &c center */ nAlign=CENTER; else if (*src == letters[10] || *src == letters[11]) /* &r right */ nAlign=RIGHT; else if (*src == letters[12] || *src == letters[13]) /* &d date */ nAlign=LEFT;
src++; } } /* Make sure all strings are null-terminated. */ for (nAlign= LEFT; nAlign <= RIGHT ; nAlign++) chBuff[nAlign][nIndex[nAlign]] = (TCHAR) 0;
}
/* GetPrinterDC() - returns printer DC or INVALID_HANDLE_VALUE if none. */
HANDLE GetPrinterDC (VOID) { LPDEVMODE lpDevMode; LPDEVNAMES lpDevNames; HDC hDC;
if( !g_PageSetupDlg.hDevNames ) /* Retrieve default printer if none selected. */ { g_PageSetupDlg.Flags |= PSD_RETURNDEFAULT; PageSetupDlg(&g_PageSetupDlg); g_PageSetupDlg.Flags &= ~PSD_RETURNDEFAULT; }
if( !g_PageSetupDlg.hDevNames ) { MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONWARNING); return INVALID_HANDLE_VALUE; }
lpDevNames= (LPDEVNAMES) GlobalLock (g_PageSetupDlg.hDevNames);
lpDevMode= NULL;
if( g_PageSetupDlg.hDevMode ) lpDevMode= (LPDEVMODE) GlobalLock( g_PageSetupDlg.hDevMode );
/* For pre 3.0 Drivers,hDevMode will be null from Commdlg so lpDevMode
* will be NULL after GlobalLock() */
/* The lpszOutput name is null so CreateDC will use the current setting
* from PrintMan. */
hDC= CreateDC (((LPTSTR)lpDevNames)+lpDevNames->wDriverOffset, ((LPTSTR)lpDevNames)+lpDevNames->wDeviceOffset, NULL, lpDevMode);
GlobalUnlock( g_PageSetupDlg.hDevNames );
if( g_PageSetupDlg.hDevMode ) GlobalUnlock( g_PageSetupDlg.hDevMode );
if( hDC == NULL ) { MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONWARNING); return INVALID_HANDLE_VALUE; }
return hDC; }
/* GetNonDefPrinterDC() - returns printer DC or INVALID_HANDLE_VALUE if none. */ /* using the name of the Printer server */
HANDLE GetNonDefPrinterDC (VOID) { HDC hDC; HANDLE hPrinter; DWORD dwBuf; DRIVER_INFO_1 *di1;
// open the printer and retrieve the driver name.
if (!OpenPrinter(szPrinterName, &hPrinter, NULL)) { return INVALID_HANDLE_VALUE; }
// get the buffer size.
GetPrinterDriver(hPrinter, NULL, 1, NULL, 0, &dwBuf); di1 = (DRIVER_INFO_1 *) LocalAlloc(LPTR, dwBuf); if (!di1) { ClosePrinter(hPrinter); return INVALID_HANDLE_VALUE; }
if (!GetPrinterDriver(hPrinter, NULL, 1, (LPBYTE) di1, dwBuf, &dwBuf)) { LocalFree(di1); ClosePrinter(hPrinter); return INVALID_HANDLE_VALUE; }
// Initialize the PageSetup dlg to default values.
// using default printer's value for another printer !!
g_PageSetupDlg.Flags |= PSD_RETURNDEFAULT; PageSetupDlg(&g_PageSetupDlg); g_PageSetupDlg.Flags &= ~PSD_RETURNDEFAULT;
// create printer dc with default initialization.
hDC= CreateDC (di1->pName, szPrinterName, NULL, NULL);
// cleanup.
LocalFree(di1); ClosePrinter(hPrinter);
if( hDC == NULL ) { MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONWARNING); return INVALID_HANDLE_VALUE; }
return hDC; }
/* PrintIt() - print the file, giving popup if some error */
void PrintIt(PRINT_DIALOG_TYPE type) { INT iError; TCHAR* szMsg= NULL; TCHAR msg[400]; // message info on error
/* print the file */
iError= NpPrint( type );
if(( iError != 0) && ( iError != SP_APPABORT ) && ( iError != SP_USERABORT ) ) { // translate any known spooler errors
if( iError == SP_OUTOFDISK ) iError= ERROR_DISK_FULL; if( iError == SP_OUTOFMEMORY ) iError= ERROR_OUTOFMEMORY; if( iError == SP_ERROR ) iError= GetLastError(); /* SP_NOTREPORTED not handled. Does it happen? */
//
// iError may be 0 because the user aborted the printing.
// Just ignore.
//
if( iError == 0 ) return;
// Get system to give reasonable error message
// These will also be internationalized.
if(!FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM, NULL, iError, GetUserDefaultLangID(), msg, // where message will end up
CharSizeOf(msg), NULL ) ) { szMsg= szCP; // couldn't get system to say; give generic msg
} else { szMsg= msg; }
AlertBox( hwndNP, szNN, szMsg, SzTitle(), MB_APPLMODAL | MB_OK | MB_ICONWARNING); } }
|