/* * npprint.c -- Code for printing from sxspad. * Copyright (C) 1984-2000 Microsoft Inc. */ #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(szFileName) ); 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 ); 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= hwndSP; 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 sxspad. // 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 sxspad 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( hwndSP, szFontTooBig, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION ); 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( hwndSP, msgbuf, CharSizeOf(msgbuf) ); EnableWindow( hwndSP, FALSE ); // Disable window to prevent reentrancy hAbortDlgWnd= CreateDialog( hInstanceSP, (LPTSTR) MAKEINTRESOURCE(IDD_ABORTPRINT), hwndSP, 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(hwndSP, 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]; TCHAR *ptr; INT page; INT nAlign=CENTER; // current string to add chars to INT foo; 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(szFileName, 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( hwndSP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION); 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( hwndSP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION); 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( hwndSP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION); 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( hwndSP, szNN, szMsg, fUntitled ? szUntitled : szFileName, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION); } }