Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1259 lines
35 KiB

  1. /*
  2. * npprint.c -- Code for printing from notepad.
  3. * Copyright (C) 1984-1995 Microsoft Inc.
  4. */
  5. #define NOMINMAX
  6. #include "precomp.h"
  7. //#define DBGPRINT
  8. /* indices into chBuff */
  9. #define LEFT 0
  10. #define CENTER 1
  11. #define RIGHT 2
  12. INT tabSize; /* Size of a tab for print device in device units*/
  13. HWND hAbortDlgWnd;
  14. INT fAbort; /* true if abort in progress */
  15. INT yPrintChar; /* height of a character */
  16. RECT rtMargin;
  17. /* left,center and right string for header or trailer */
  18. #define MAXTITLE MAX_PATH
  19. TCHAR chBuff[RIGHT+1][MAXTITLE];
  20. /* date and time stuff for headers */
  21. #define MAXDATE MAX_PATH
  22. #define MAXTIME MAX_PATH
  23. TCHAR szFormattedDate[MAXDATE]=TEXT("Y"); // formatted date (may be internationalized)
  24. TCHAR szFormattedTime[MAXTIME]=TEXT("Y"); // formatted time (may be internaltionalized)
  25. SYSTEMTIME PrintTime; // time we started printing
  26. INT xPrintRes; // printer resolution in x direction
  27. INT yPrintRes; // printer resolution in y direction
  28. INT yPixInch; // pixels/inch
  29. INT xPhysRes; // physical resolution x of paper
  30. INT yPhysRes; // physical resolution y of paper
  31. INT xPhysOff; // physical offset x
  32. INT yPhysOff; // physical offset y
  33. INT dyTop; // width of top border (pixels)
  34. INT dyBottom; // width of bottom border
  35. INT dxLeft; // width of left border
  36. INT dxRight; // width of right border
  37. INT iPageNum; // global page number currently being printed
  38. /* define a type for NUM and the base */
  39. typedef long NUM;
  40. #define BASE 100L
  41. /* converting in/out of fixed point */
  42. #define NumToShort(x,s) (LOWORD(((x) + (s)) / BASE))
  43. #define NumRemToShort(x) (LOWORD((x) % BASE))
  44. /* rounding options for NumToShort */
  45. #define NUMFLOOR 0
  46. #define NUMROUND (BASE/2)
  47. #define NUMCEILING (BASE-1)
  48. #define ROUND(x) NumToShort(x,NUMROUND)
  49. #define FLOOR(x) NumToShort(x,NUMFLOOR)
  50. /* Unit conversion */
  51. #define InchesToCM(x) (((x) * 254L + 50) / 100)
  52. #define CMToInches(x) (((x) * 100L + 127) / 254)
  53. void DestroyAbortWnd(void) ;
  54. VOID TranslateString(TCHAR *);
  55. BOOL CALLBACK AbortProc(HDC hPrintDC, INT reserved)
  56. {
  57. MSG msg;
  58. while( !fAbort && PeekMessage((LPMSG)&msg, NULL, 0, 0, TRUE) )
  59. {
  60. if( !hAbortDlgWnd || !IsDialogMessage( hAbortDlgWnd, (LPMSG)&msg ) )
  61. {
  62. TranslateMessage( (LPMSG)&msg );
  63. DispatchMessage( (LPMSG)&msg );
  64. }
  65. }
  66. return( !fAbort );
  67. UNREFERENCED_PARAMETER(hPrintDC);
  68. UNREFERENCED_PARAMETER(reserved);
  69. }
  70. INT_PTR CALLBACK AbortDlgProc(
  71. HWND hwnd,
  72. UINT msg,
  73. WPARAM wParam,
  74. LPARAM lParam)
  75. {
  76. static HMENU hSysMenu;
  77. switch( msg )
  78. {
  79. case WM_COMMAND:
  80. fAbort= TRUE;
  81. DestroyAbortWnd();
  82. return( TRUE );
  83. case WM_INITDIALOG:
  84. hSysMenu= GetSystemMenu( hwnd, FALSE );
  85. SetDlgItemText( hwnd, ID_FILENAME,
  86. fUntitled ? szUntitled : PFileInPath(szFileName) );
  87. SetFocus( hwnd );
  88. return( TRUE );
  89. case WM_INITMENU:
  90. EnableMenuItem( hSysMenu, (WORD)SC_CLOSE, (DWORD)MF_GRAYED );
  91. return( TRUE );
  92. }
  93. return( FALSE );
  94. UNREFERENCED_PARAMETER(wParam);
  95. UNREFERENCED_PARAMETER(lParam);
  96. }
  97. /*
  98. * print out the translated header/footer string in proper position.
  99. * uses globals xPrintWidth, ...
  100. *
  101. * returns 1 if line was printed, otherwise 0.
  102. */
  103. INT PrintHeaderFooter (HDC hDC, INT nHF)
  104. {
  105. SIZE Size; // to compute the width of each string
  106. INT yPos; // y position to print
  107. INT xPos; // x position to print
  108. if( *chPageText[nHF] == 0 ) // see if anything to do
  109. return 0; // we didn't print
  110. TranslateString( chPageText[nHF] );
  111. // figure out the y position we are printing
  112. if( nHF == HEADER )
  113. yPos= dyTop;
  114. else
  115. yPos= yPrintRes - dyBottom - yPrintChar;
  116. // print out the various strings
  117. // N.B. could overprint which seems ok for now
  118. if( *chBuff[LEFT] ) // left string
  119. {
  120. TextOut( hDC, dxLeft, yPos, chBuff[LEFT], lstrlen(chBuff[LEFT]) );
  121. }
  122. if( *chBuff[CENTER] ) // center string
  123. {
  124. GetTextExtentPoint32( hDC, chBuff[CENTER], lstrlen(chBuff[CENTER]), &Size );
  125. xPos= (xPrintRes-dxRight+dxLeft)/2 - Size.cx/2;
  126. TextOut( hDC, xPos, yPos, chBuff[CENTER], lstrlen(chBuff[CENTER]) );
  127. }
  128. if( *chBuff[RIGHT] ) // right string
  129. {
  130. GetTextExtentPoint32( hDC, chBuff[RIGHT], lstrlen(chBuff[RIGHT]), &Size );
  131. xPos= xPrintRes - dxRight - Size.cx;
  132. TextOut( hDC, xPos, yPos, chBuff[RIGHT], lstrlen(chBuff[RIGHT]) );
  133. }
  134. return 1; // we did print something
  135. }
  136. /*
  137. * GetResolutions
  138. *
  139. * Gets printer resolutions.
  140. * sets globals: xPrintRes, yPrintRes, yPixInch
  141. *
  142. */
  143. VOID GetResolutions(HDC hPrintDC)
  144. {
  145. xPrintRes = GetDeviceCaps( hPrintDC, HORZRES );
  146. yPrintRes = GetDeviceCaps( hPrintDC, VERTRES );
  147. yPixInch = GetDeviceCaps( hPrintDC, LOGPIXELSY );
  148. xPhysRes = GetDeviceCaps( hPrintDC, PHYSICALWIDTH );
  149. yPhysRes = GetDeviceCaps( hPrintDC, PHYSICALHEIGHT );
  150. xPhysOff = GetDeviceCaps( hPrintDC, PHYSICALOFFSETX );
  151. yPhysOff = GetDeviceCaps( hPrintDC, PHYSICALOFFSETY );
  152. }
  153. /* GetMoreText
  154. *
  155. * Gets the next line of text from the MLE, returning a pointer
  156. * to the beginning and just past the end.
  157. *
  158. * linenum - index into MLE (IN)
  159. * pStartText - start of MLE (IN)
  160. * ppsStr - pointer to where to put pointer to start of text (OUT)
  161. * ppEOL - pointer to where to put pointer to just past EOL (OUT)
  162. *
  163. */
  164. VOID GetMoreText( INT linenum, PTCHAR pStartText, PTCHAR* ppsStr, PTCHAR* ppEOL )
  165. {
  166. INT Offset; // offset in 'chars' into edit buffer
  167. INT nChars; // number of chars in line
  168. Offset= (INT)SendMessage( hwndEdit, EM_LINEINDEX, linenum, 0 );
  169. nChars= (INT)SendMessage( hwndEdit, EM_LINELENGTH, Offset, 0 );
  170. *ppsStr= pStartText + Offset;
  171. *ppEOL= (pStartText+Offset) + nChars;
  172. }
  173. #ifdef DBGPRINT
  174. TCHAR dbuf[100];
  175. VOID ShowMargins( HDC hPrintDC )
  176. {
  177. INT xPrintRes, yPrintRes;
  178. RECT rct;
  179. HBRUSH hBrush;
  180. xPrintRes= GetDeviceCaps( hPrintDC, HORZRES );
  181. yPrintRes= GetDeviceCaps( hPrintDC, VERTRES );
  182. hBrush= GetStockObject( BLACK_BRUSH );
  183. if ( hBrush )
  184. {
  185. SetRect( &rct, 0,0,xPrintRes-1, yPrintRes-1 );
  186. FrameRect( hPrintDC, &rct, hBrush );
  187. SetRect( &rct, dxLeft, dyTop, xPrintRes-dxRight, yPrintRes-dyBottom );
  188. FrameRect( hPrintDC, &rct, hBrush );
  189. }
  190. }
  191. VOID PrintLogFont( LOGFONT lf )
  192. {
  193. wsprintf(dbuf,TEXT("lfHeight %d\n"), lf.lfHeight ); ODS(dbuf);
  194. wsprintf(dbuf,TEXT("lfWidth %d\n"), lf.lfWidth ); ODS(dbuf);
  195. wsprintf(dbuf,TEXT("lfEscapement %d\n"), lf. lfEscapement ); ODS(dbuf);
  196. wsprintf(dbuf,TEXT("lfOrientation %d\n"), lf.lfOrientation ); ODS(dbuf);
  197. wsprintf(dbuf,TEXT("lfWeight %d\n"), lf.lfWeight ); ODS(dbuf);
  198. wsprintf(dbuf,TEXT("lfItalic %d\n"), lf.lfItalic ); ODS(dbuf);
  199. wsprintf(dbuf,TEXT("lfUnderline %d\n"), lf.lfUnderline ); ODS(dbuf);
  200. wsprintf(dbuf,TEXT("lfStrikeOut %d\n"), lf.lfStrikeOut ); ODS(dbuf);
  201. wsprintf(dbuf,TEXT("lfCharSet %d\n"), lf.lfCharSet ); ODS(dbuf);
  202. wsprintf(dbuf,TEXT("lfOutPrecision %d\n"), lf.lfOutPrecision ); ODS(dbuf);
  203. wsprintf(dbuf,TEXT("lfClipPrecison %d\n"), lf.lfClipPrecision ); ODS(dbuf);
  204. wsprintf(dbuf,TEXT("lfQuality %d\n"), lf.lfQuality ); ODS(dbuf);
  205. wsprintf(dbuf,TEXT("lfPitchAndFamily %d\n"), lf.lfPitchAndFamily); ODS(dbuf);
  206. wsprintf(dbuf,TEXT("lfFaceName %s\n"), lf.lfFaceName ); ODS(dbuf);
  207. }
  208. #endif
  209. // GetPrinterDCviaDialog
  210. //
  211. // Use the common dialog PrintDlgEx() function to get a printer DC to print to.
  212. //
  213. // Returns: valid HDC or INVALID_HANDLE_VALUE if error.
  214. //
  215. HDC GetPrinterDCviaDialog( VOID )
  216. {
  217. PRINTDLGEX pdTemp;
  218. HDC hDC;
  219. HRESULT hRes;
  220. //
  221. // Get the page setup information
  222. //
  223. if( !g_PageSetupDlg.hDevNames ) /* Retrieve default printer if none selected. */
  224. {
  225. g_PageSetupDlg.Flags |= (PSD_RETURNDEFAULT|PSD_NOWARNING );
  226. PageSetupDlg(&g_PageSetupDlg);
  227. g_PageSetupDlg.Flags &= ~(PSD_RETURNDEFAULT|PSD_NOWARNING);
  228. }
  229. //
  230. // Initialize the dialog structure
  231. //
  232. ZeroMemory( &pdTemp, sizeof(pdTemp) );
  233. pdTemp.lStructSize= sizeof(pdTemp);
  234. pdTemp.hwndOwner= hwndNP;
  235. pdTemp.nStartPage= START_PAGE_GENERAL;
  236. // FEATURE: We turn off multiple copies seen 'notepad' doesn't do it.
  237. // But this will work on many print drivers esp. if using EMF printing.
  238. // We may want to add our own code to do the multiple copies
  239. pdTemp.Flags= PD_NOPAGENUMS | PD_RETURNDC | PD_NOCURRENTPAGE |
  240. PD_USEDEVMODECOPIESANDCOLLATE |
  241. PD_NOSELECTION | 0;
  242. // if use set printer in PageSetup, use it here too.
  243. if( g_PageSetupDlg.hDevMode )
  244. {
  245. pdTemp.hDevMode= g_PageSetupDlg.hDevMode;
  246. }
  247. if( g_PageSetupDlg.hDevNames )
  248. {
  249. pdTemp.hDevNames= g_PageSetupDlg.hDevNames;
  250. }
  251. //
  252. // let user select printer
  253. //
  254. hRes= PrintDlgEx( &pdTemp );
  255. //
  256. // get DC if valid return
  257. //
  258. hDC= INVALID_HANDLE_VALUE;
  259. if( hRes == S_OK )
  260. {
  261. if( (pdTemp.dwResultAction == PD_RESULT_PRINT) || (pdTemp.dwResultAction == PD_RESULT_APPLY) )
  262. {
  263. if( pdTemp.dwResultAction == PD_RESULT_PRINT )
  264. {
  265. hDC= pdTemp.hDC;
  266. }
  267. //
  268. // Get the page setup information for the printer selected in case it was
  269. // the first printer added by the user through notepad.
  270. //
  271. if( !g_PageSetupDlg.hDevMode )
  272. {
  273. g_PageSetupDlg.Flags |= (PSD_RETURNDEFAULT|PSD_NOWARNING );
  274. PageSetupDlg(&g_PageSetupDlg);
  275. g_PageSetupDlg.Flags &= ~(PSD_RETURNDEFAULT|PSD_NOWARNING);
  276. }
  277. // change devmode if user pressed print or apply
  278. g_PageSetupDlg.hDevMode= pdTemp.hDevMode;
  279. g_PageSetupDlg.hDevNames= pdTemp.hDevNames;
  280. }
  281. }
  282. // FEATURE: free hDevNames
  283. return( hDC );
  284. }
  285. INT NpPrint( PRINT_DIALOG_TYPE type)
  286. {
  287. HDC hPrintDC;
  288. SetCursor( hWaitCursor );
  289. switch( type )
  290. {
  291. case UseDialog:
  292. hPrintDC= GetPrinterDCviaDialog();
  293. break;
  294. case NoDialogNonDefault:
  295. hPrintDC= GetNonDefPrinterDC();
  296. break;
  297. case DoNotUseDialog:
  298. default:
  299. hPrintDC= GetPrinterDC();
  300. break;
  301. }
  302. if( hPrintDC == INVALID_HANDLE_VALUE )
  303. {
  304. SetCursor( hStdCursor );
  305. return( 0 ); // message already given
  306. }
  307. return( NpPrintGivenDC( hPrintDC ) );
  308. }
  309. INT NpPrintGivenDC( HDC hPrintDC )
  310. {
  311. HANDLE hText= NULL; // handle to MLE text
  312. HFONT hPrintFont= NULL; // font to print with
  313. HANDLE hPrevFont= NULL; // previous font in hPrintDC
  314. BOOL fPageStarted= FALSE; // true if StartPage called for this page
  315. BOOL fDocStarted= FALSE; // true if StartDoc called
  316. PTCHAR pStartText= NULL; // start of edit text (locked hText)
  317. TEXTMETRIC Metrics;
  318. TCHAR msgbuf[MAX_PATH]; // Document name for tracking print job
  319. INT nLinesPerPage; // not inc. header and footer
  320. // iErr will contain the first error discovered ie it is sticky
  321. // This will be the value returned by this function.
  322. // It does not need to translate SP_* errors except for SP_ERROR which should be
  323. // GetLastError() right after it is first detected.
  324. INT iErr=0; // error return
  325. DOCINFO DocInfo;
  326. LOGFONT lfPrintFont; // local version of FontStruct
  327. LCID lcid; // locale id
  328. fAbort = FALSE;
  329. hAbortDlgWnd= NULL;
  330. SetCursor( hWaitCursor );
  331. GetResolutions( hPrintDC );
  332. // Get the time and date for use in the header or trailer.
  333. // We use the GetDateFormat and GetTimeFormat to get the
  334. // internationalized versions.
  335. GetLocalTime( &PrintTime ); // use local, not gmt
  336. lcid= GetUserDefaultLCID();
  337. GetDateFormat( lcid, DATE_LONGDATE, &PrintTime, NULL, szFormattedDate, MAXDATE );
  338. GetTimeFormat( lcid, 0, &PrintTime, NULL, szFormattedTime, MAXTIME );
  339. /*
  340. * This part is to select the current font to the printer device.
  341. * We have to change the height because FontStruct was created
  342. * assuming the display. Using the remembered pointsize, calculate
  343. * the new height.
  344. */
  345. lfPrintFont= FontStruct; // make local copy
  346. lfPrintFont.lfHeight= -(iPointSize*yPixInch)/(72*10);
  347. lfPrintFont.lfWidth= 0;
  348. //
  349. // convert margins to pixels
  350. // ptPaperSize is the physical paper size, not the printable area.
  351. // do the mapping in physical units
  352. //
  353. SetMapMode( hPrintDC, MM_ANISOTROPIC );
  354. SetViewportExtEx( hPrintDC,
  355. xPhysRes,
  356. yPhysRes,
  357. NULL );
  358. SetWindowExtEx( hPrintDC,
  359. g_PageSetupDlg.ptPaperSize.x,
  360. g_PageSetupDlg.ptPaperSize.y,
  361. NULL );
  362. rtMargin = g_PageSetupDlg.rtMargin;
  363. LPtoDP( hPrintDC, (LPPOINT) &rtMargin, 2 );
  364. SetMapMode( hPrintDC,MM_TEXT ); // restore to mm_text mode
  365. hPrintFont= CreateFontIndirect(&lfPrintFont);
  366. if( !hPrintFont )
  367. {
  368. goto ErrorExit;
  369. }
  370. hPrevFont= SelectObject( hPrintDC, hPrintFont );
  371. if( !hPrevFont )
  372. {
  373. goto ErrorExit;
  374. }
  375. SetBkMode( hPrintDC, TRANSPARENT );
  376. if( !GetTextMetrics( hPrintDC, (LPTEXTMETRIC) &Metrics ) )
  377. {
  378. goto ErrorExit;
  379. }
  380. // The font may not a scalable (say on a bubblejet printer)
  381. // In this case, just pick some font
  382. // For example, FixedSys 9 pt would be non-scalable
  383. if( !(Metrics.tmPitchAndFamily & (TMPF_VECTOR | TMPF_TRUETYPE )) )
  384. {
  385. // remove just created font
  386. hPrintFont= SelectObject( hPrintDC, hPrevFont ); // get old font
  387. DeleteObject( hPrintFont );
  388. memset( lfPrintFont.lfFaceName, 0, LF_FACESIZE*sizeof(TCHAR) );
  389. hPrintFont= CreateFontIndirect( &lfPrintFont );
  390. if( !hPrintFont )
  391. {
  392. goto ErrorExit;
  393. }
  394. hPrevFont= SelectObject( hPrintDC, hPrintFont );
  395. if( !hPrevFont )
  396. {
  397. goto ErrorExit;
  398. }
  399. if( !GetTextMetrics( hPrintDC, (LPTEXTMETRIC) &Metrics ) )
  400. {
  401. goto ErrorExit;
  402. }
  403. }
  404. yPrintChar= Metrics.tmHeight+Metrics.tmExternalLeading; /* the height */
  405. tabSize = Metrics.tmAveCharWidth * 8; /* 8 ave char width pixels for tabs */
  406. // compute margins in pixels
  407. dxLeft= max(rtMargin.left - xPhysOff,0);
  408. dxRight= max(rtMargin.right - (xPhysRes - xPrintRes - xPhysOff), 0 );
  409. dyTop= max(rtMargin.top - yPhysOff,0);
  410. dyBottom= max(rtMargin.bottom - (yPhysRes - yPrintRes - yPhysOff), 0 );
  411. #ifdef DBGPRINT
  412. {
  413. TCHAR dbuf[100];
  414. RECT rt= g_PageSetupDlg.rtMargin;
  415. POINT pt;
  416. wsprintf(dbuf,TEXT("Print pOffx %d pOffy %d\n"),
  417. GetDeviceCaps(hPrintDC, PHYSICALOFFSETX),
  418. GetDeviceCaps(hPrintDC, PHYSICALOFFSETY));
  419. ODS(dbuf);
  420. wsprintf(dbuf,TEXT("PHYSICALWIDTH: %d\n"), xPhysRes);
  421. ODS(dbuf);
  422. wsprintf(dbuf,TEXT("HORZRES: %d\n"),xPrintRes);
  423. ODS(dbuf);
  424. wsprintf(dbuf,TEXT("PHYSICALOFFSETX: %d\n"),xPhysOff);
  425. ODS(dbuf);
  426. wsprintf(dbuf,TEXT("LOGPIXELSX: %d\n"),
  427. GetDeviceCaps(hPrintDC,LOGPIXELSX));
  428. ODS(dbuf);
  429. GetViewportOrgEx( hPrintDC, (LPPOINT) &pt );
  430. wsprintf(dbuf,TEXT("Viewport org: %d %d\n"), pt.x, pt.y );
  431. ODS(dbuf);
  432. GetWindowOrgEx( hPrintDC, (LPPOINT) &pt );
  433. wsprintf(dbuf,TEXT("Window org: %d %d\n"), pt.x, pt.y );
  434. ODS(dbuf);
  435. wsprintf(dbuf,TEXT("PrintRes x: %d y: %d\n"),xPrintRes, yPrintRes);
  436. ODS(dbuf);
  437. wsprintf(dbuf,TEXT("PaperSize x: %d y: %d\n"),
  438. g_PageSetupDlg.ptPaperSize.x,
  439. g_PageSetupDlg.ptPaperSize.y );
  440. ODS(dbuf);
  441. wsprintf(dbuf,TEXT("unit margins: l: %d r: %d t: %d b: %d\n"),
  442. rt.left, rt.right, rt.top, rt.bottom);
  443. ODS(dbuf);
  444. wsprintf(dbuf,TEXT("pixel margins: l: %d r: %d t: %d b: %d\n"),
  445. rtMargin.left, rtMargin.right, rtMargin.top, rtMargin.bottom);
  446. ODS(dbuf);
  447. wsprintf(dbuf,TEXT("dxLeft %d dxRight %d\n"),dxLeft,dxRight);
  448. ODS(dbuf);
  449. wsprintf(dbuf,TEXT("dyTop %d dyBot %d\n"),dyTop,dyBottom);
  450. ODS(dbuf);
  451. }
  452. #endif
  453. /* Number of lines on a page with margins */
  454. /* two lines are used by header and footer */
  455. nLinesPerPage = ((yPrintRes - dyTop - dyBottom) / yPrintChar);
  456. if( *chPageText[HEADER] )
  457. nLinesPerPage--;
  458. if( *chPageText[FOOTER] )
  459. nLinesPerPage--;
  460. /*
  461. ** There was a bug in NT once where a printer driver would
  462. ** return a font that was larger than the page size which
  463. ** would then cause Notepad to constantly print blank pages
  464. ** To keep from doing this we check to see if we can fit ANYTHING
  465. ** on a page, if not then there is a problem so quit. MarkRi 8/92
  466. */
  467. if( nLinesPerPage <= 0 )
  468. {
  469. FontTooBig:
  470. MessageBox( hwndNP, szFontTooBig, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION );
  471. SetLastError(0); // no error
  472. ErrorExit:
  473. iErr= GetLastError(); // remember the first error
  474. ExitWithThisError: // preserve iErr (return SP_* errors)
  475. if( hPrevFont )
  476. {
  477. SelectObject( hPrintDC, hPrevFont );
  478. DeleteObject( hPrintFont );
  479. }
  480. if( pStartText ) // were able to lock hText
  481. LocalUnlock( hText );
  482. if( fPageStarted )
  483. {
  484. if( EndPage( hPrintDC ) <= 0 )
  485. {
  486. // if iErr not already set then set it to the new error code.
  487. if( iErr == 0 )
  488. {
  489. iErr= GetLastError();
  490. }
  491. }
  492. }
  493. if( fDocStarted )
  494. {
  495. if( fAbort ) {
  496. AbortDoc( hPrintDC );
  497. }
  498. else {
  499. if( EndDoc( hPrintDC ) <= 0 )
  500. {
  501. // if iErr not already set then set it to the new error code.
  502. if (iErr == 0)
  503. {
  504. iErr= GetLastError();
  505. }
  506. }
  507. }
  508. }
  509. DeleteDC( hPrintDC );
  510. DestroyAbortWnd();
  511. SetCursor( hStdCursor );
  512. if (!fAbort)
  513. {
  514. return( iErr );
  515. }
  516. else
  517. {
  518. return( SP_USERABORT );
  519. }
  520. }
  521. if( (iErr= SetAbortProc (hPrintDC, AbortProc)) < 0 )
  522. {
  523. goto ExitWithThisError;
  524. }
  525. // get printer to MLE text
  526. hText= (HANDLE) SendMessage( hwndEdit, EM_GETHANDLE, 0, 0 );
  527. if( !hText )
  528. {
  529. goto ErrorExit;
  530. }
  531. pStartText= LocalLock( hText );
  532. if( !pStartText )
  533. {
  534. goto ErrorExit;
  535. }
  536. GetWindowText( hwndNP, msgbuf, CharSizeOf(msgbuf) );
  537. EnableWindow( hwndNP, FALSE ); // Disable window to prevent reentrancy
  538. hAbortDlgWnd= CreateDialog( hInstanceNP,
  539. (LPTSTR) MAKEINTRESOURCE(IDD_ABORTPRINT),
  540. hwndNP,
  541. AbortDlgProc);
  542. if( !hAbortDlgWnd )
  543. {
  544. goto ErrorExit;
  545. }
  546. DocInfo.cbSize= sizeof(DOCINFO);
  547. DocInfo.lpszDocName= msgbuf;
  548. DocInfo.lpszOutput= NULL;
  549. DocInfo.lpszDatatype= NULL; // Type of data used to record print job
  550. DocInfo.fwType= 0; // not DI_APPBANDING
  551. SetLastError(0); // clear error so it reflects errors in the future
  552. if( StartDoc( hPrintDC, &DocInfo ) <= 0 )
  553. {
  554. iErr = GetLastError();
  555. goto ExitWithThisError;
  556. }
  557. fDocStarted= TRUE;
  558. // Basicly, this is just a loop surrounding the DrawTextEx API.
  559. // We have to calculate the printable area which will not include
  560. // the header and footer area.
  561. {
  562. INT iTextLeft; // amount of text left to print
  563. INT iSta; // status
  564. UINT dwDTFormat; // drawtext flags
  565. DRAWTEXTPARAMS dtParm; // drawtext control
  566. RECT rect; // rectangle to draw in
  567. UINT dwDTRigh = 0; // drawtext flags (RTL)
  568. iPageNum= 1;
  569. fPageStarted= FALSE;
  570. // calculate the size of the printable area for the text
  571. // not including the header and footer
  572. ZeroMemory( &rect, sizeof(rect) );
  573. rect.left= dxLeft; rect.right= xPrintRes-dxRight;
  574. rect.top= dyTop; rect.bottom= yPrintRes-dyBottom;
  575. if( *chPageText[HEADER] != 0 )
  576. {
  577. rect.top += yPrintChar;
  578. }
  579. if( *chPageText[FOOTER] != 0 )
  580. {
  581. rect.bottom -= yPrintChar;
  582. }
  583. iTextLeft= lstrlen(pStartText);
  584. //Get the edit control direction.
  585. if (GetWindowLong(hwndEdit, GWL_EXSTYLE) & WS_EX_RTLREADING)
  586. dwDTRigh = DT_RIGHT | DT_RTLREADING;
  587. while( !fAbort && (iTextLeft>0) )
  588. {
  589. #define MAXSTATUS 100
  590. TCHAR szPagePrinting[MAXSTATUS+1];
  591. // update abort dialog box to inform user where we are in the printing
  592. _sntprintf( szPagePrinting, MAXSTATUS, szCurrentPage, iPageNum );
  593. SetDlgItemText( hAbortDlgWnd, ID_PAGENUMBER, szPagePrinting );
  594. PrintHeaderFooter( hPrintDC, HEADER );
  595. ZeroMemory( &dtParm, sizeof(dtParm) );
  596. dtParm.cbSize= sizeof(dtParm);
  597. dtParm.iTabLength= tabSize;
  598. dwDTFormat= DT_EDITCONTROL | DT_LEFT | DT_EXPANDTABS | DT_NOPREFIX |
  599. DT_WORDBREAK | dwDTRigh | 0;
  600. if( StartPage( hPrintDC ) <= 0 )
  601. {
  602. iErr= GetLastError();
  603. goto ExitWithThisError;
  604. }
  605. fPageStarted= TRUE;
  606. #ifdef DBGPRINT
  607. ShowMargins(hPrintDC);
  608. #endif
  609. /* Ignore errors in printing. EndPage or StartPage will find them */
  610. iSta= DrawTextEx( hPrintDC,
  611. pStartText,
  612. iTextLeft,
  613. &rect,
  614. dwDTFormat,
  615. &dtParm);
  616. PrintHeaderFooter( hPrintDC, FOOTER );
  617. if( EndPage( hPrintDC ) <= 0 )
  618. {
  619. iErr= GetLastError();
  620. goto ExitWithThisError;
  621. }
  622. fPageStarted= FALSE;
  623. iPageNum++;
  624. // if we can't print a single character (too big perhaps)
  625. // just bail now.
  626. if( dtParm.uiLengthDrawn == 0 )
  627. {
  628. goto FontTooBig;
  629. }
  630. pStartText += dtParm.uiLengthDrawn;
  631. iTextLeft -= dtParm.uiLengthDrawn;
  632. }
  633. }
  634. iErr=0; // no errors
  635. goto ExitWithThisError;
  636. }
  637. VOID DestroyAbortWnd (void)
  638. {
  639. EnableWindow(hwndNP, TRUE);
  640. DestroyWindow(hAbortDlgWnd);
  641. hAbortDlgWnd = NULL;
  642. }
  643. const DWORD s_PageSetupHelpIDs[] = {
  644. ID_HEADER_LABEL, IDH_PAGE_HEADER,
  645. ID_HEADER, IDH_PAGE_HEADER,
  646. ID_FOOTER_LABEL, IDH_PAGE_FOOTER,
  647. ID_FOOTER, IDH_PAGE_FOOTER,
  648. 0, 0
  649. };
  650. /*******************************************************************************
  651. *
  652. * PageSetupHookProc
  653. *
  654. * DESCRIPTION:
  655. * Callback procedure for the PageSetup common dialog box.
  656. *
  657. * PARAMETERS:
  658. * hWnd, handle of PageSetup window.
  659. * Message,
  660. * wParam,
  661. * lParam,
  662. * (returns),
  663. *
  664. *******************************************************************************/
  665. UINT_PTR CALLBACK PageSetupHookProc(
  666. HWND hWnd,
  667. UINT Message,
  668. WPARAM wParam,
  669. LPARAM lParam
  670. )
  671. {
  672. INT id; /* ID of dialog edit controls */
  673. POINT pt;
  674. switch (Message)
  675. {
  676. case WM_INITDIALOG:
  677. for (id = ID_HEADER; id <= ID_FOOTER; id++)
  678. {
  679. SendDlgItemMessage(hWnd, id, EM_LIMITTEXT, PT_LEN-1, 0L);
  680. SetDlgItemText(hWnd, id, chPageText[id - ID_HEADER]);
  681. }
  682. SendDlgItemMessage(hWnd, ID_HEADER, EM_SETSEL, 0,
  683. MAKELONG(0, PT_LEN-1));
  684. return TRUE;
  685. case WM_DESTROY:
  686. // We don't know if the user hit OK or Cancel, so we don't
  687. // want to replace our real copies until we know! We _should_ get
  688. // a notification from the common dialog code!
  689. for( id = ID_HEADER; id <= ID_FOOTER; id++ )
  690. {
  691. GetDlgItemText(hWnd, id, chPageTextTemp[id - ID_HEADER],PT_LEN);
  692. }
  693. break;
  694. case WM_HELP:
  695. //
  696. // We only want to intercept help messages for controls that we are
  697. // responsible for.
  698. //
  699. id = GetDlgCtrlID(((LPHELPINFO) lParam)-> hItemHandle);
  700. if (id < ID_HEADER || id > ID_FOOTER_LABEL)
  701. break;
  702. WinHelp(((LPHELPINFO) lParam)-> hItemHandle, szHelpFile,
  703. HELP_WM_HELP, (UINT_PTR) (LPVOID) s_PageSetupHelpIDs);
  704. return TRUE;
  705. case WM_CONTEXTMENU:
  706. //
  707. // If the user clicks on any of our labels, then the wParam will
  708. // be the hwnd of the dialog, not the static control. WinHelp()
  709. // handles this, but because we hook the dialog, we must catch it
  710. // first.
  711. //
  712. if( hWnd == (HWND) wParam )
  713. {
  714. GetCursorPos(&pt);
  715. ScreenToClient(hWnd, &pt);
  716. wParam = (WPARAM) ChildWindowFromPoint(hWnd, pt);
  717. }
  718. //
  719. // We only want to intercept help messages for controls that we are
  720. // responsible for.
  721. //
  722. id = GetDlgCtrlID((HWND) wParam);
  723. if (id < ID_HEADER || id > ID_FOOTER_LABEL)
  724. break;
  725. WinHelp((HWND) wParam, szHelpFile, HELP_CONTEXTMENU,
  726. (UINT_PTR) (LPVOID) s_PageSetupHelpIDs);
  727. return TRUE;
  728. }
  729. return FALSE;
  730. }
  731. /***************************************************************************
  732. * VOID TranslateString(TCHAR *src)
  733. *
  734. * purpose:
  735. * translate a header/footer strings
  736. *
  737. * supports the following:
  738. *
  739. * && insert a & char
  740. * &f current file name or (untitled)
  741. * &d date in Day Month Year
  742. * &t time
  743. * &p page number
  744. * &p+num set first page number to num
  745. *
  746. * Alignment:
  747. * &l, &c, &r for left, center, right
  748. *
  749. * params:
  750. * IN/OUT src this is the string to translate
  751. *
  752. *
  753. * used by:
  754. * Header Footer stuff
  755. *
  756. * uses:
  757. * lots of c lib stuff
  758. *
  759. ***************************************************************************/
  760. VOID TranslateString (TCHAR * src)
  761. {
  762. TCHAR buf[MAX_PATH];
  763. TCHAR *ptr;
  764. INT page;
  765. INT nAlign=CENTER; // current string to add chars to
  766. INT foo;
  767. INT nIndex[RIGHT+1]; // current lengths of (left,center,right)
  768. struct tm *newtime;
  769. time_t long_time;
  770. INT iLen; // length of strings
  771. nIndex[LEFT] = 0;
  772. nIndex[CENTER] = 0;
  773. nIndex[RIGHT] = 0;
  774. /* Get the time we need in case we use &t. */
  775. time (&long_time);
  776. newtime = localtime (&long_time);
  777. while (*src) /* look at all of source */
  778. {
  779. while (*src && *src != TEXT('&'))
  780. {
  781. chBuff[nAlign][nIndex[nAlign]] = *src++;
  782. nIndex[nAlign] += 1;
  783. }
  784. if (*src == TEXT('&')) /* is it the escape char? */
  785. {
  786. src++;
  787. if (*src == szLetters[0] || *src == szLetters[1])
  788. { /* &f file name (no path) */
  789. if (!fUntitled)
  790. {
  791. GetFileTitle(szFileName, buf, CharSizeOf(buf));
  792. }
  793. else
  794. {
  795. lstrcpy(buf, szUntitled);
  796. }
  797. /* Copy to the currently aligned string. */
  798. if( nIndex[nAlign] + lstrlen(buf) < MAXTITLE )
  799. {
  800. lstrcpy( chBuff[nAlign] + nIndex[nAlign], buf );
  801. /* Update insertion position. */
  802. nIndex[nAlign] += lstrlen (buf);
  803. }
  804. }
  805. else if (*src == szLetters[2] || *src == szLetters[3]) /* &P or &P+num page */
  806. {
  807. src++;
  808. page = 0;
  809. if (*src == TEXT('+')) /* &p+num case */
  810. {
  811. src++;
  812. while (_istdigit(*src))
  813. {
  814. /* Convert to int on-the-fly*/
  815. page = (10*page) + (*src) - TEXT('0');
  816. src++;
  817. }
  818. }
  819. wsprintf( buf, TEXT("%d"), iPageNum+page ); // convert to chars
  820. if( nIndex[nAlign] + lstrlen(buf) < MAXTITLE )
  821. {
  822. lstrcpy( chBuff[nAlign] + nIndex[nAlign], buf );
  823. nIndex[nAlign] += lstrlen (buf);
  824. }
  825. src--;
  826. }
  827. else if (*src == szLetters[4] || *src == szLetters[5]) /* &t time */
  828. {
  829. iLen= lstrlen( szFormattedTime );
  830. /* extract time */
  831. if( nIndex[nAlign] + iLen < MAXTITLE )
  832. {
  833. _tcsncpy (chBuff[nAlign] + nIndex[nAlign], szFormattedTime, iLen);
  834. nIndex[nAlign] += iLen;
  835. }
  836. }
  837. else if (*src == szLetters[6] || *src == szLetters[7]) /* &d date */
  838. {
  839. iLen= lstrlen( szFormattedDate );
  840. /* extract day month day */
  841. if( nIndex[nAlign] + iLen < MAXTITLE )
  842. {
  843. _tcsncpy (chBuff[nAlign] + nIndex[nAlign], szFormattedDate, iLen);
  844. nIndex[nAlign] += iLen;
  845. }
  846. }
  847. else if (*src == TEXT('&')) /* quote a single & */
  848. {
  849. if( nIndex[nAlign] + 1 < MAXTITLE )
  850. {
  851. chBuff[nAlign][nIndex[nAlign]] = TEXT('&');
  852. nIndex[nAlign] += 1;
  853. }
  854. }
  855. /* Set the alignment for whichever has last occured. */
  856. else if (*src == szLetters[8] || *src == szLetters[9]) /* &c center */
  857. nAlign=CENTER;
  858. else if (*src == szLetters[10] || *src == szLetters[11]) /* &r right */
  859. nAlign=RIGHT;
  860. else if (*src == szLetters[12] || *src == szLetters[13]) /* &d date */
  861. nAlign=LEFT;
  862. src++;
  863. }
  864. }
  865. /* Make sure all strings are null-terminated. */
  866. for (nAlign= LEFT; nAlign <= RIGHT ; nAlign++)
  867. chBuff[nAlign][nIndex[nAlign]] = (TCHAR) 0;
  868. }
  869. /* GetPrinterDC() - returns printer DC or INVALID_HANDLE_VALUE if none. */
  870. HANDLE GetPrinterDC (VOID)
  871. {
  872. LPDEVMODE lpDevMode;
  873. LPDEVNAMES lpDevNames;
  874. HDC hDC;
  875. if( !g_PageSetupDlg.hDevNames ) /* Retrieve default printer if none selected. */
  876. {
  877. g_PageSetupDlg.Flags |= PSD_RETURNDEFAULT;
  878. PageSetupDlg(&g_PageSetupDlg);
  879. g_PageSetupDlg.Flags &= ~PSD_RETURNDEFAULT;
  880. }
  881. if( !g_PageSetupDlg.hDevNames )
  882. {
  883. MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  884. return INVALID_HANDLE_VALUE;
  885. }
  886. lpDevNames= (LPDEVNAMES) GlobalLock (g_PageSetupDlg.hDevNames);
  887. lpDevMode= NULL;
  888. if( g_PageSetupDlg.hDevMode )
  889. lpDevMode= (LPDEVMODE) GlobalLock( g_PageSetupDlg.hDevMode );
  890. /* For pre 3.0 Drivers,hDevMode will be null from Commdlg so lpDevMode
  891. * will be NULL after GlobalLock()
  892. */
  893. /* The lpszOutput name is null so CreateDC will use the current setting
  894. * from PrintMan.
  895. */
  896. hDC= CreateDC (((LPTSTR)lpDevNames)+lpDevNames->wDriverOffset,
  897. ((LPTSTR)lpDevNames)+lpDevNames->wDeviceOffset,
  898. NULL,
  899. lpDevMode);
  900. GlobalUnlock( g_PageSetupDlg.hDevNames );
  901. if( g_PageSetupDlg.hDevMode )
  902. GlobalUnlock( g_PageSetupDlg.hDevMode );
  903. if( hDC == NULL )
  904. {
  905. MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  906. return INVALID_HANDLE_VALUE;
  907. }
  908. return hDC;
  909. }
  910. /* GetNonDefPrinterDC() - returns printer DC or INVALID_HANDLE_VALUE if none. */
  911. /* using the name of the Printer server */
  912. HANDLE GetNonDefPrinterDC (VOID)
  913. {
  914. HDC hDC;
  915. HANDLE hPrinter;
  916. DWORD dwBuf;
  917. DRIVER_INFO_1 *di1;
  918. // open the printer and retrieve the driver name.
  919. if (!OpenPrinter(szPrinterName, &hPrinter, NULL))
  920. {
  921. return INVALID_HANDLE_VALUE;
  922. }
  923. // get the buffer size.
  924. GetPrinterDriver(hPrinter, NULL, 1, NULL, 0, &dwBuf);
  925. di1 = (DRIVER_INFO_1 *) LocalAlloc(LPTR, dwBuf);
  926. if (!di1)
  927. {
  928. ClosePrinter(hPrinter);
  929. return INVALID_HANDLE_VALUE;
  930. }
  931. if (!GetPrinterDriver(hPrinter, NULL, 1, (LPBYTE) di1, dwBuf, &dwBuf))
  932. {
  933. LocalFree(di1);
  934. ClosePrinter(hPrinter);
  935. return INVALID_HANDLE_VALUE;
  936. }
  937. // Initialize the PageSetup dlg to default values.
  938. // using default printer's value for another printer !!
  939. g_PageSetupDlg.Flags |= PSD_RETURNDEFAULT;
  940. PageSetupDlg(&g_PageSetupDlg);
  941. g_PageSetupDlg.Flags &= ~PSD_RETURNDEFAULT;
  942. // create printer dc with default initialization.
  943. hDC= CreateDC (di1->pName, szPrinterName, NULL, NULL);
  944. // cleanup.
  945. LocalFree(di1);
  946. ClosePrinter(hPrinter);
  947. if( hDC == NULL )
  948. {
  949. MessageBox( hwndNP, szLoadDrvFail, szNN, MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  950. return INVALID_HANDLE_VALUE;
  951. }
  952. return hDC;
  953. }
  954. /* PrintIt() - print the file, giving popup if some error */
  955. void PrintIt(PRINT_DIALOG_TYPE type)
  956. {
  957. INT iError;
  958. TCHAR* szMsg= NULL;
  959. TCHAR msg[400]; // message info on error
  960. /* print the file */
  961. iError= NpPrint( type );
  962. if(( iError != 0) &&
  963. ( iError != SP_APPABORT ) &&
  964. ( iError != SP_USERABORT ) )
  965. {
  966. // translate any known spooler errors
  967. if( iError == SP_OUTOFDISK ) iError= ERROR_DISK_FULL;
  968. if( iError == SP_OUTOFMEMORY ) iError= ERROR_OUTOFMEMORY;
  969. if( iError == SP_ERROR ) iError= GetLastError();
  970. /* SP_NOTREPORTED not handled. Does it happen? */
  971. //
  972. // iError may be 0 because the user aborted the printing.
  973. // Just ignore.
  974. //
  975. if( iError == 0 ) return;
  976. // Get system to give reasonable error message
  977. // These will also be internationalized.
  978. if(!FormatMessage( FORMAT_MESSAGE_IGNORE_INSERTS |
  979. FORMAT_MESSAGE_FROM_SYSTEM,
  980. NULL,
  981. iError,
  982. GetUserDefaultLangID(),
  983. msg, // where message will end up
  984. CharSizeOf(msg), NULL ) )
  985. {
  986. szMsg= szCP; // couldn't get system to say; give generic msg
  987. }
  988. else
  989. {
  990. szMsg= msg;
  991. }
  992. AlertBox( hwndNP, szNN, szMsg, fUntitled ? szUntitled : szFileName,
  993. MB_APPLMODAL | MB_OK | MB_ICONEXCLAMATION);
  994. }
  995. }