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.

479 lines
13 KiB

  1. // Print.cpp - Functions to handle MSInfo printing of the text report.
  2. //
  3. // Copyright (c) 1998-1999 Microsoft Corporation
  4. #include "stdafx.h"
  5. #include "DataSrc.h"
  6. #include "Resource.h"
  7. #include "DataObj.h"
  8. #include "CompData.h"
  9. #include <afxext.h>
  10. #ifdef _DEBUG
  11. #define new DEBUG_NEW
  12. #undef THIS_FILE
  13. static char THIS_FILE[] = __FILE__;
  14. #endif
  15. /*
  16. * PreparePrintDialog - Do all initialization required before the print
  17. * dialog is displayed, most notably calculating the page count.
  18. *
  19. * History: a-jsari 3/17/98 Initial version
  20. */
  21. BOOL CDataSource::RefreshPrintData(CPrintDialog * pdlgPrint, CFolder * pfolSelection)
  22. {
  23. // FIX: Make calculation of line length device independent.
  24. LPTSTR szLine;
  25. int cLength = 84;
  26. int cLineCount = 57;
  27. unsigned short cPage = 0;
  28. CFolder * pPrintRoot = NULL;
  29. if (pdlgPrint->PrintSelection() && pfolSelection)
  30. pPrintRoot = pfolSelection;
  31. else
  32. pPrintRoot = GetRootNode();
  33. if (m_pPrintContent != NULL)
  34. delete m_pPrintContent;
  35. m_pPrintContent = new CMSInfoMemoryFile();
  36. ASSERT(m_pPrintContent != NULL);
  37. if (m_pPrintContent == NULL)
  38. ::AfxThrowMemoryException();
  39. if (m_pPrintInfo != NULL) {
  40. // Set this pointer to NULL so it doesn't delete the
  41. // pointer we're storing internally.
  42. m_pPrintInfo->m_pPD = NULL;
  43. // This prevents the delete below from asserting.
  44. m_pPrintInfo->m_strPageDesc = _T("");
  45. delete m_pPrintInfo;
  46. m_pPrintInfo = NULL;
  47. }
  48. m_pPrintInfo = new CPrintInfo;
  49. ASSERT(m_pPrintInfo != NULL);
  50. if (m_pPrintInfo == NULL) {
  51. delete m_pPrintContent;
  52. m_pPrintContent = NULL;
  53. ::AfxThrowMemoryException();
  54. }
  55. m_pPrintInfo->m_nCurPage = 0;
  56. m_pPrintInfo->m_pPD = pdlgPrint;
  57. if (FAILED(WriteOutput(m_pPrintContent, pPrintRoot)))
  58. return FALSE;
  59. m_pPrintContent->SeekToBegin();
  60. szLine = new TCHAR[cLength + 1];
  61. m_fEndOfFile = FALSE;
  62. while (!m_fEndOfFile) {
  63. int iLine = cLineCount;
  64. ++cPage;
  65. while (iLine--) {
  66. GetLine(szLine, cLength);
  67. if (m_fEndOfFile)
  68. goto WhileEnd;
  69. }
  70. }
  71. WhileEnd:
  72. delete [] szLine;
  73. pdlgPrint->m_pd.nMaxPage = cPage;
  74. if (pdlgPrint->m_pd.nToPage > pdlgPrint->m_pd.nMaxPage)
  75. pdlgPrint->m_pd.nToPage = pdlgPrint->m_pd.nMaxPage;
  76. return TRUE;
  77. }
  78. /*
  79. * PrintReport - Send the report data to the printer.
  80. *
  81. * History: a-jsari 12/9/97 Initial version.
  82. */
  83. BOOL CDataSource::PrintReport(CPrintDialog *pdlgPrint, CFolder *pfolSelection)
  84. {
  85. BOOL fReturn;
  86. do {
  87. int nResult = BeginPrinting(pdlgPrint, pfolSelection);
  88. if (nResult < 0)
  89. break;
  90. m_pPrintContent->SeekToBegin();
  91. while (m_pPrintInfo->m_bContinuePrinting)
  92. PrintPage(pdlgPrint);
  93. EndPrinting();
  94. fReturn = TRUE;
  95. } while (FALSE);
  96. delete m_pPrintContent;
  97. m_pPrintContent = NULL;
  98. delete m_pPrintInfo;
  99. m_pPrintInfo = NULL;
  100. return fReturn;
  101. }
  102. /*
  103. * BeginPrinting - Do the initialization required to print the file.
  104. *
  105. * History: a-jsari 12/30/97 Thieved from msishell's msiview.cpp,
  106. * modified to allow page ranges.
  107. */
  108. int CDataSource::BeginPrinting(CPrintDialog *pdlgPrint, CFolder *pfolSelection)
  109. {
  110. ASSERT(m_pPrintContent != NULL);
  111. if (m_pPrintContent == NULL) {
  112. m_fEndOfFile = TRUE;
  113. m_pPrintInfo->m_bContinuePrinting = FALSE;
  114. ::AfxThrowMemoryException();
  115. }
  116. if (m_pDC != NULL) {
  117. delete m_pDC;
  118. m_pDC = NULL;
  119. }
  120. m_pDC = new CDC;
  121. ASSERT(m_pDC != NULL);
  122. if (m_pDC == NULL) ::AfxThrowMemoryException();
  123. if (m_pprinterFont != NULL) {
  124. delete m_pprinterFont;
  125. m_pprinterFont = NULL;
  126. }
  127. m_pprinterFont = new CFont;
  128. ASSERT(m_pprinterFont != NULL);
  129. if (m_pprinterFont == NULL) ::AfxThrowMemoryException();
  130. #if 0
  131. m_strHeaderLeft = pScope->MachineName();
  132. #endif
  133. CString strFormat;
  134. COleDateTime datetime;
  135. strFormat.LoadString(IDS_PRINT_HDR_RIGHT_CURRENT);
  136. datetime = COleDateTime::GetCurrentTime();
  137. m_strHeaderRight = datetime.Format(strFormat);
  138. m_strFooterCenter.LoadString(IDS_PRINT_FTR_CTR);
  139. // Reset the end of file member.
  140. m_fEndOfFile = FALSE;
  141. // Create the font for printing. Read font information from string
  142. // resources, to allow the localizers to control what font is
  143. // used for printing. Set the variables for the default font to use.
  144. int nHeight = 10;
  145. int nWeight = FW_NORMAL;
  146. BYTE nCharSet = DEFAULT_CHARSET;
  147. BYTE nPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
  148. CString strFace = "Courier New";
  149. // Load string resources to see if we should use other values
  150. // than the defaults.
  151. CString strHeight, strWeight, strCharSet, strPitchAndFamily, strFaceName;
  152. strHeight.LoadString(IDS_PRINT_FONT_HEIGHT);
  153. strWeight.LoadString(IDS_PRINT_FONT_WEIGHT);
  154. strCharSet.LoadString(IDS_PRINT_FONT_CHARSET);
  155. strPitchAndFamily.LoadString(IDS_PRINT_FONT_PITCHANDFAMILY);
  156. strFaceName.LoadString(IDS_PRINT_FONT_FACENAME);
  157. if (!strHeight.IsEmpty() && ::_ttol(strHeight))
  158. nHeight = ::_ttoi(strHeight);
  159. if (!strWeight.IsEmpty())
  160. nWeight = ::_ttoi(strWeight);
  161. if (!strCharSet.IsEmpty())
  162. nCharSet = (BYTE) ::_ttoi(strCharSet);
  163. if (!strPitchAndFamily.IsEmpty())
  164. nPitchAndFamily = (BYTE) ::_ttoi(strPitchAndFamily);
  165. strFaceName.TrimLeft();
  166. if (!strFaceName.IsEmpty() && strFaceName != CString("facename"))
  167. strFace = strFaceName;
  168. CString strDriver = pdlgPrint->GetDriverName();
  169. CString strDevice = pdlgPrint->GetDeviceName();
  170. CString strPort = pdlgPrint->GetPortName();
  171. LPDEVMODE pdevMode = pdlgPrint->GetDevMode();
  172. VERIFY(m_pDC->CreateDC(strDriver, strDevice, strPort, pdevMode));
  173. // Convert the height from points to a value specific to the printer.
  174. nHeight = -((m_pDC->GetDeviceCaps (LOGPIXELSY) * nHeight) / 72);
  175. // Create the font object.
  176. VERIFY(m_pprinterFont->CreateFont(nHeight, 0, 0, 0, nWeight, 0, 0, 0,
  177. nCharSet, OUT_CHARACTER_PRECIS, CLIP_CHARACTER_PRECIS,
  178. DEFAULT_QUALITY, nPitchAndFamily, strFace));
  179. m_pPrintInfo->m_rectDraw.SetRect(0, 0, m_pDC->GetDeviceCaps(HORZRES),
  180. m_pDC->GetDeviceCaps(VERTRES));
  181. m_pDC->DPtoLP(&m_pPrintInfo->m_rectDraw);
  182. m_pPrintInfo->m_bContinuePrinting = TRUE;
  183. CString strDocName;
  184. CString strOutput;
  185. DOCINFO diJob;
  186. diJob.cbSize = sizeof(DOCINFO);
  187. diJob.lpszDocName = strDocName;
  188. diJob.lpszOutput = strOutput;
  189. return m_pDC->StartDoc(&diJob);
  190. }
  191. /*
  192. * OnEndPrinting - Clean up anything we allocated for the print job. Specifically,
  193. * delete the CMemFile holding the content.
  194. *
  195. * History: a-jsari 12/30/97 Thieved from MSIShell's msiview.cpp
  196. */
  197. void CDataSource::EndPrinting()
  198. {
  199. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  200. if (m_pPrintContent != NULL)
  201. {
  202. delete m_pPrintContent;
  203. m_pPrintContent = NULL;
  204. }
  205. int nResult = m_pDC->EndDoc();
  206. ASSERT(nResult >= 0);
  207. if (nResult < 0) {
  208. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  209. CString strError, strTitle;
  210. switch(nResult) {
  211. case SP_OUTOFDISK:
  212. VERIFY(strError.LoadString(IDS_PRINT_NODISK));
  213. break;
  214. case SP_OUTOFMEMORY:
  215. VERIFY(strError.LoadString(IDS_PRINT_NOMEMORY));
  216. break;
  217. case SP_USERABORT:
  218. VERIFY(strError.LoadString(IDS_PRINT_USERABORTED));
  219. break;
  220. case SP_ERROR:
  221. default:
  222. VERIFY(strError.LoadString(IDS_PRINT_GENERIC));
  223. break;
  224. }
  225. strTitle.LoadString(IDS_DESCRIPTION);
  226. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK);
  227. }
  228. VERIFY(m_pprinterFont->DeleteObject());
  229. VERIFY(m_pDC->DeleteDC());
  230. }
  231. //---------------------------------------------------------------------------
  232. // In this function, we use two rectangles: rectOuter is what we consider
  233. // the printable area of the page, and includes headers and footers.
  234. // rectInner is the rectange we actually print the content in (doesn't
  235. // include headers or footers).
  236. //
  237. // TBD: add header and footer
  238. // TBD: add error checking
  239. // TBD: fix intelegence issues and speed this up
  240. // TBD: insure that 80 columns will always fit
  241. //---------------------------------------------------------------------------
  242. #define TOP_MARGIN 2540/2 // HIMETRIC for 1/2 inch
  243. #define BOTTOM_MARGIN 2540/2 // HIMETRIC for 1/2 inch
  244. #define LEFT_MARGIN 2540/2 // HIMETRIC for 1/2 inch
  245. #define RIGHT_MARGIN 2540/2 // HIMETRIC for 1/2 inch
  246. /*
  247. * GetLine - Copy a line of data from m_pPrintContent into szLineBuffer.
  248. *
  249. * History: a-jsari 3/16/98 Initial version.
  250. */
  251. void CDataSource::GetLine(LPTSTR szLineBuffer, int cSize)
  252. {
  253. for (int i = 0; i < cSize; i++)
  254. {
  255. try {
  256. m_pPrintContent->ReadTchar(szLineBuffer[i]);
  257. } catch (...)
  258. {
  259. m_pPrintInfo->m_bContinuePrinting = FALSE;
  260. m_fEndOfFile = TRUE;
  261. szLineBuffer[i] = '\0';
  262. break;
  263. }
  264. if (szLineBuffer[i] == '\t')
  265. {
  266. // Convert tabs into spaces for printing.
  267. szLineBuffer[i] = ' ';
  268. }
  269. else if (szLineBuffer[i] == '\r')
  270. {
  271. i--;
  272. }
  273. else if (szLineBuffer[i] == '\n')
  274. {
  275. szLineBuffer[i] = '\0';
  276. break;
  277. }
  278. }
  279. }
  280. /*
  281. * GetTextSize - Get the sizes of the text.
  282. *
  283. * History: a-jsari 3/16/98 Initial version.
  284. */
  285. void CDataSource::GetTextSize(int &cLineLength, int &cCharHeight, CRect &rectOuter, CRect &rectText)
  286. {
  287. TEXTMETRIC tm;
  288. m_pDC->GetTextMetrics(&tm);
  289. cCharHeight = tm.tmHeight + tm.tmExternalLeading;
  290. // Take the actual print area (in pInfo) and adjust it for the
  291. // header and footer.
  292. rectOuter = m_pPrintInfo->m_rectDraw;
  293. CSize sizeLeftTop(LEFT_MARGIN, TOP_MARGIN);
  294. CSize sizeRightBottom(RIGHT_MARGIN, BOTTOM_MARGIN);
  295. m_pDC->HIMETRICtoDP(&sizeLeftTop);
  296. m_pDC->HIMETRICtoDP(&sizeRightBottom);
  297. rectOuter.DeflateRect(sizeLeftTop.cx, sizeLeftTop.cy, sizeRightBottom.cx, sizeRightBottom.cy);
  298. rectText = rectOuter;
  299. rectText.DeflateRect(0, cCharHeight * 4);
  300. // Get the number of characters which will fit on a line (use the average, because this
  301. // might not be a monospaced font). Note: it's possible that text could be cut off
  302. // if a line consisted of very wide characters. This is unlikely because the font
  303. // used SHOULD be monospace (for alignment of text, etc.).
  304. cLineLength = rectText.Width() / tm.tmAveCharWidth;
  305. }
  306. /*
  307. * PrintPage - Write one page to the printer Device Context.
  308. *
  309. * History: a-jsari 12/30/97 Thieved from msishell's msiview.cpp.
  310. */
  311. void CDataSource::PrintPage(CPrintDialog *pdlgPrint)
  312. {
  313. int cLineLength;
  314. int cy = 0, cyCharHeight;
  315. LPTSTR szLineBuffer;
  316. CRect rectOuter, rectInner;
  317. ASSERT(m_pPrintContent != NULL);
  318. if (m_pPrintContent == NULL)
  319. {
  320. m_fEndOfFile = TRUE;
  321. m_pPrintInfo->m_bContinuePrinting = FALSE;
  322. return;
  323. }
  324. // Select the font used for printing.
  325. CGdiObject* pOldFont = m_pDC->SelectObject(m_pprinterFont);
  326. // this makes a small font: CGdiObject *pOldFont = pDC->SelectStockObject(ANSI_FIXED_FONT);
  327. // Compute the height of each character (we'll need the text metric).
  328. GetTextSize(cLineLength, cyCharHeight, rectOuter, rectInner);
  329. ++m_pPrintInfo->m_nCurPage;
  330. if (!(pdlgPrint->PrintAll() || pdlgPrint->PrintSelection())
  331. && m_pPrintInfo->m_nCurPage > m_pPrintInfo->GetToPage()) {
  332. m_pPrintInfo->m_bContinuePrinting = FALSE;
  333. m_pDC->SelectObject(pOldFont);
  334. return;
  335. }
  336. // Allocate the buffer of character to hold a single line of the print out.
  337. szLineBuffer = new TCHAR[cLineLength + 1];
  338. szLineBuffer[cLineLength] = (TCHAR)'\0';
  339. if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
  340. || m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage()) {
  341. m_pDC->StartPage();
  342. // Draw the header.
  343. m_pDC->TextOut(rectOuter.left, rectOuter.top, m_strHeaderLeft);
  344. int cxHeaderRight = rectOuter.right - m_pDC->GetTextExtent(m_strHeaderRight).cx;
  345. m_pDC->TextOut(cxHeaderRight, rectOuter.top, m_strHeaderRight);
  346. }
  347. // Process the output a line at a time, until either we have emptied out
  348. // the memfile, or we have gotten to the bottom of this page.
  349. while (!m_fEndOfFile)
  350. {
  351. if (cy + cyCharHeight > rectInner.Height())
  352. break;
  353. GetLine(szLineBuffer, cLineLength);
  354. if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
  355. || m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage())
  356. m_pDC->TextOut(rectInner.left, rectInner.top + cy, szLineBuffer, ::_tcslen(szLineBuffer));
  357. cy += cyCharHeight;
  358. }
  359. if (pdlgPrint->PrintAll() || pdlgPrint->PrintSelection()
  360. || m_pPrintInfo->m_nCurPage >= m_pPrintInfo->GetFromPage()) {
  361. // Draw the footer.
  362. CString strActualFooter;
  363. strActualFooter.Format(m_strFooterCenter, m_pPrintInfo->m_nCurPage);
  364. int cxFooterCenter = (rectOuter.Width() - m_pDC->GetTextExtent(strActualFooter).cx) / 2;
  365. m_pDC->TextOut(rectOuter.left + cxFooterCenter, rectOuter.bottom - cyCharHeight, strActualFooter);
  366. int nResult = m_pDC->EndPage();
  367. ASSERT(nResult >= 0);
  368. }
  369. #if 0
  370. if (nResult < 0) {
  371. AFX_MANAGE_STATE(::AfxGetStaticModuleState());
  372. CString strError;
  373. switch (nResult) {
  374. case SP_APPABORT:
  375. VERIFY(strError.LoadString(IDS_PRINT_APPABORTED));
  376. break;
  377. case SP_USERABORT:
  378. VERIFY(strError.LoadString(IDS_PRINT_USERABORTED));
  379. break;
  380. case SP_OUTOFDISK:
  381. VERIFY(strError.LoadString(IDS_PRINT_NODISK));
  382. break;
  383. case SP_OUTOFMEMORY:
  384. VERIFY(strError.LoadString(IDS_PRINT_NOMEMORY));
  385. break;
  386. case SP_ERROR:
  387. default:
  388. VERIFY(strError.LoadString(IDS_PRINT_GENERIC));
  389. break;
  390. }
  391. strTitle.LoadString(IDS_DESCRIPTION)
  392. ::MessageBox( ::AfxGetMainWnd()->GetSafeHwnd(), strError, strTitle, MB_OK);
  393. }
  394. // Clean up.
  395. #endif
  396. delete [] szLineBuffer;
  397. m_pDC->SelectObject(pOldFont);
  398. }