home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / vc98 / mfc / src / viewprnt.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1998-06-16  |  10.8 KB  |  380 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_PRINT_SEG
  14. #pragma code_seg(AFX_PRINT_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // Printing Dialog
  24.  
  25. class CPrintingDialog : public CDialog
  26. {
  27. public:
  28.     //{{AFX_DATA(CPrintingDialog)
  29.     enum { IDD = AFX_IDD_PRINTDLG };
  30.     //}}AFX_DATA
  31.     CPrintingDialog::CPrintingDialog(CWnd* pParent)
  32.         {
  33.             Create(CPrintingDialog::IDD, pParent);      // modeless !
  34.             _afxWinState->m_bUserAbort = FALSE;
  35.         }
  36.     virtual ~CPrintingDialog() { }
  37.  
  38.     virtual BOOL OnInitDialog();
  39.     virtual void OnCancel();
  40. };
  41.  
  42. BOOL CALLBACK _AfxAbortProc(HDC, int)
  43. {
  44.     _AFX_WIN_STATE* pWinState = _afxWinState;
  45.     MSG msg;
  46.     while (!pWinState->m_bUserAbort &&
  47.         ::PeekMessage(&msg, NULL, NULL, NULL, PM_NOREMOVE))
  48.     {
  49.         if (!AfxGetThread()->PumpMessage())
  50.             return FALSE;   // terminate if WM_QUIT received
  51.     }
  52.     return !pWinState->m_bUserAbort;
  53. }
  54.  
  55. BOOL CPrintingDialog::OnInitDialog()
  56. {
  57.     SetWindowText(AfxGetAppName());
  58.     CenterWindow();
  59.     return CDialog::OnInitDialog();
  60. }
  61.  
  62. void CPrintingDialog::OnCancel()
  63. {
  64.     _afxWinState->m_bUserAbort = TRUE;  // flag that user aborted print
  65.     CDialog::OnCancel();
  66. }
  67.  
  68. /////////////////////////////////////////////////////////////////////////////
  69. // CView printing commands
  70.  
  71. BOOL CView::DoPreparePrinting(CPrintInfo* pInfo)
  72. {
  73.     ASSERT(pInfo != NULL);
  74.     ASSERT(pInfo->m_pPD != NULL);
  75.  
  76.     if (pInfo->m_pPD->m_pd.nMinPage > pInfo->m_pPD->m_pd.nMaxPage)
  77.         pInfo->m_pPD->m_pd.nMaxPage = pInfo->m_pPD->m_pd.nMinPage;
  78.  
  79.     // don't prompt the user if we're doing print preview, printing directly,
  80.     // or printing via IPrint and have been instructed not to ask
  81.  
  82.     CWinApp* pApp = AfxGetApp();
  83.     if (pInfo->m_bPreview || pInfo->m_bDirect ||
  84.         (pInfo->m_bDocObject && !(pInfo->m_dwFlags & PRINTFLAG_PROMPTUSER)))
  85.     {
  86.         if (pInfo->m_pPD->m_pd.hDC == NULL)
  87.         {
  88.             // if no printer set then, get default printer DC and create DC without calling
  89.             //   print dialog.
  90.             if (!pApp->GetPrinterDeviceDefaults(&pInfo->m_pPD->m_pd))
  91.             {
  92.                 // bring up dialog to alert the user they need to install a printer.
  93.                 if (!pInfo->m_bDocObject || (pInfo->m_dwFlags & PRINTFLAG_MAYBOTHERUSER))
  94.                     if (pApp->DoPrintDialog(pInfo->m_pPD) != IDOK)
  95.                         return FALSE;
  96.             }
  97.  
  98.             if (pInfo->m_pPD->m_pd.hDC == NULL)
  99.             {
  100.                 // call CreatePrinterDC if DC was not created by above
  101.                 if (pInfo->m_pPD->CreatePrinterDC() == NULL)
  102.                     return FALSE;
  103.             }
  104.         }
  105.  
  106.         // set up From and To page range from Min and Max
  107.         pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage();
  108.         pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage();
  109.     }
  110.     else
  111.     {
  112.         // otherwise, bring up the print dialog and allow user to change things
  113.         // preset From-To range same as Min-Max range
  114.         pInfo->m_pPD->m_pd.nFromPage = (WORD)pInfo->GetMinPage();
  115.         pInfo->m_pPD->m_pd.nToPage = (WORD)pInfo->GetMaxPage();
  116.  
  117.         if (pApp->DoPrintDialog(pInfo->m_pPD) != IDOK)
  118.             return FALSE;       // do not print
  119.     }
  120.  
  121.     ASSERT(pInfo->m_pPD != NULL);
  122.     ASSERT(pInfo->m_pPD->m_pd.hDC != NULL);
  123.     if (pInfo->m_pPD->m_pd.hDC == NULL)
  124.         return FALSE;
  125.  
  126.     pInfo->m_nNumPreviewPages = pApp->m_nNumPreviewPages;
  127.     VERIFY(pInfo->m_strPageDesc.LoadString(AFX_IDS_PREVIEWPAGEDESC));
  128.     return TRUE;
  129. }
  130.  
  131. void CView::OnFilePrint()
  132. {
  133.     // get default print info
  134.     CPrintInfo printInfo;
  135.     ASSERT(printInfo.m_pPD != NULL);    // must be set
  136.  
  137.     if (LOWORD(GetCurrentMessage()->wParam) == ID_FILE_PRINT_DIRECT)
  138.     {
  139.         CCommandLineInfo* pCmdInfo = AfxGetApp()->m_pCmdInfo;
  140.  
  141.         if (pCmdInfo != NULL)
  142.         {
  143.             if (pCmdInfo->m_nShellCommand == CCommandLineInfo::FilePrintTo)
  144.             {
  145.                 printInfo.m_pPD->m_pd.hDC = ::CreateDC(pCmdInfo->m_strDriverName,
  146.                     pCmdInfo->m_strPrinterName, pCmdInfo->m_strPortName, NULL);
  147.                 if (printInfo.m_pPD->m_pd.hDC == NULL)
  148.                 {
  149.                     AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
  150.                     return;
  151.                 }
  152.             }
  153.         }
  154.  
  155.         printInfo.m_bDirect = TRUE;
  156.     }
  157.  
  158.     if (OnPreparePrinting(&printInfo))
  159.     {
  160.         // hDC must be set (did you remember to call DoPreparePrinting?)
  161.         ASSERT(printInfo.m_pPD->m_pd.hDC != NULL);
  162.  
  163.         // gather file to print to if print-to-file selected
  164.         CString strOutput;
  165.         if (printInfo.m_pPD->m_pd.Flags & PD_PRINTTOFILE && !printInfo.m_bDocObject)
  166.         {
  167.             // construct CFileDialog for browsing
  168.             CString strDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULTEXT));
  169.             CString strPrintDef(MAKEINTRESOURCE(AFX_IDS_PRINTDEFAULT));
  170.             CString strFilter(MAKEINTRESOURCE(AFX_IDS_PRINTFILTER));
  171.             CString strCaption(MAKEINTRESOURCE(AFX_IDS_PRINTCAPTION));
  172.             CFileDialog dlg(FALSE, strDef, strPrintDef,
  173.                 OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, strFilter);
  174.             dlg.m_ofn.lpstrTitle = strCaption;
  175.  
  176.             if (dlg.DoModal() != IDOK)
  177.                 return;
  178.  
  179.             // set output device to resulting path name
  180.             strOutput = dlg.GetPathName();
  181.         }
  182.  
  183.         // set up document info and start the document printing process
  184.         CString strTitle;
  185.         CDocument* pDoc = GetDocument();
  186.         if (pDoc != NULL)
  187.             strTitle = pDoc->GetTitle();
  188.         else
  189.             GetParentFrame()->GetWindowText(strTitle);
  190.         if (strTitle.GetLength() > 31)
  191.             strTitle.ReleaseBuffer(31);
  192.         DOCINFO docInfo;
  193.         memset(&docInfo, 0, sizeof(DOCINFO));
  194.         docInfo.cbSize = sizeof(DOCINFO);
  195.         docInfo.lpszDocName = strTitle;
  196.         CString strPortName;
  197.         int nFormatID;
  198.         if (strOutput.IsEmpty())
  199.         {
  200.             docInfo.lpszOutput = NULL;
  201.             strPortName = printInfo.m_pPD->GetPortName();
  202.             nFormatID = AFX_IDS_PRINTONPORT;
  203.         }
  204.         else
  205.         {
  206.             docInfo.lpszOutput = strOutput;
  207.             AfxGetFileTitle(strOutput,
  208.                 strPortName.GetBuffer(_MAX_PATH), _MAX_PATH);
  209.             nFormatID = AFX_IDS_PRINTTOFILE;
  210.         }
  211.  
  212.         // setup the printing DC
  213.         CDC dcPrint;
  214.         if (!printInfo.m_bDocObject)
  215.         {
  216.             dcPrint.Attach(printInfo.m_pPD->m_pd.hDC);  // attach printer dc
  217.             dcPrint.m_bPrinting = TRUE;
  218.         }
  219.         OnBeginPrinting(&dcPrint, &printInfo);
  220.  
  221.         if (!printInfo.m_bDocObject)
  222.             dcPrint.SetAbortProc(_AfxAbortProc);
  223.  
  224.         // disable main window while printing & init printing status dialog
  225.         AfxGetMainWnd()->EnableWindow(FALSE);
  226.         CPrintingDialog dlgPrintStatus(this);
  227.  
  228.         CString strTemp;
  229.         dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_DOCNAME, strTitle);
  230.         dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PRINTERNAME,
  231.             printInfo.m_pPD->GetDeviceName());
  232.         AfxFormatString1(strTemp, nFormatID, strPortName);
  233.         dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PORTNAME, strTemp);
  234.         dlgPrintStatus.ShowWindow(SW_SHOW);
  235.         dlgPrintStatus.UpdateWindow();
  236.  
  237.         // start document printing process
  238.         if (!printInfo.m_bDocObject && dcPrint.StartDoc(&docInfo) == SP_ERROR)
  239.         {
  240.             // enable main window before proceeding
  241.             AfxGetMainWnd()->EnableWindow(TRUE);
  242.  
  243.             // cleanup and show error message
  244.             OnEndPrinting(&dcPrint, &printInfo);
  245.             dlgPrintStatus.DestroyWindow();
  246.             dcPrint.Detach();   // will be cleaned up by CPrintInfo destructor
  247.             AfxMessageBox(AFX_IDP_FAILED_TO_START_PRINT);
  248.             return;
  249.         }
  250.  
  251.         // Guarantee values are in the valid range
  252.         UINT nEndPage = printInfo.GetToPage();
  253.         UINT nStartPage = printInfo.GetFromPage();
  254.  
  255.         if (nEndPage < printInfo.GetMinPage())
  256.             nEndPage = printInfo.GetMinPage();
  257.         if (nEndPage > printInfo.GetMaxPage())
  258.             nEndPage = printInfo.GetMaxPage();
  259.  
  260.         if (nStartPage < printInfo.GetMinPage())
  261.             nStartPage = printInfo.GetMinPage();
  262.         if (nStartPage > printInfo.GetMaxPage())
  263.             nStartPage = printInfo.GetMaxPage();
  264.  
  265.         int nStep = (nEndPage >= nStartPage) ? 1 : -1;
  266.         nEndPage = (nEndPage == 0xffff) ? 0xffff : nEndPage + nStep;
  267.  
  268.         VERIFY(strTemp.LoadString(AFX_IDS_PRINTPAGENUM));
  269.  
  270.         // If it's a doc object, we don't loop page-by-page
  271.         // because doc objects don't support that kind of levity.
  272.  
  273.         BOOL bError = FALSE;
  274.         if (printInfo.m_bDocObject)
  275.         {
  276.             OnPrepareDC(&dcPrint, &printInfo);
  277.             OnPrint(&dcPrint, &printInfo);
  278.         }
  279.         else
  280.         {
  281.             // begin page printing loop
  282.             for (printInfo.m_nCurPage = nStartPage;
  283.                 printInfo.m_nCurPage != nEndPage; printInfo.m_nCurPage += nStep)
  284.             {
  285.                 OnPrepareDC(&dcPrint, &printInfo);
  286.  
  287.                 // check for end of print
  288.                 if (!printInfo.m_bContinuePrinting)
  289.                     break;
  290.  
  291.                 // write current page
  292.                 TCHAR szBuf[80];
  293.                 wsprintf(szBuf, strTemp, printInfo.m_nCurPage);
  294.                 dlgPrintStatus.SetDlgItemText(AFX_IDC_PRINT_PAGENUM, szBuf);
  295.  
  296.                 // set up drawing rect to entire page (in logical coordinates)
  297.                 printInfo.m_rectDraw.SetRect(0, 0,
  298.                     dcPrint.GetDeviceCaps(HORZRES),
  299.                     dcPrint.GetDeviceCaps(VERTRES));
  300.                 dcPrint.DPtoLP(&printInfo.m_rectDraw);
  301.  
  302.                 // attempt to start the current page
  303.                 if (dcPrint.StartPage() < 0)
  304.                 {
  305.                     bError = TRUE;
  306.                     break;
  307.                 }
  308.  
  309.                 // must call OnPrepareDC on newer versions of Windows because
  310.                 // StartPage now resets the device attributes.
  311.                 if (afxData.bMarked4)
  312.                     OnPrepareDC(&dcPrint, &printInfo);
  313.  
  314.                 ASSERT(printInfo.m_bContinuePrinting);
  315.  
  316.                 // page successfully started, so now render the page
  317.                 OnPrint(&dcPrint, &printInfo);
  318.                 if (dcPrint.EndPage() < 0 || !_AfxAbortProc(dcPrint.m_hDC, 0))
  319.                 {
  320.                     bError = TRUE;
  321.                     break;
  322.                 }
  323.             }
  324.         }
  325.  
  326.         // cleanup document printing process
  327.         if (!printInfo.m_bDocObject)
  328.         {
  329.             if (!bError)
  330.                 dcPrint.EndDoc();
  331.             else
  332.                 dcPrint.AbortDoc();
  333.         }
  334.  
  335.         AfxGetMainWnd()->EnableWindow();    // enable main window
  336.  
  337.         OnEndPrinting(&dcPrint, &printInfo);    // clean up after printing
  338.         dlgPrintStatus.DestroyWindow();
  339.  
  340.         dcPrint.Detach();   // will be cleaned up by CPrintInfo destructor
  341.     }
  342. }
  343.  
  344. /////////////////////////////////////////////////////////////////////////////
  345. // CPrintInfo helper structure
  346.  
  347. CPrintInfo::CPrintInfo()
  348. {
  349.     m_pPD = new CPrintDialog(FALSE, PD_ALLPAGES | PD_USEDEVMODECOPIES |
  350.         PD_NOSELECTION);
  351.  
  352.     ASSERT(m_pPD->m_pd.hDC == NULL);
  353.  
  354.     SetMinPage(1);              // one based page numbers
  355.     SetMaxPage(0xffff);         // unknown how many pages
  356.  
  357.     m_nCurPage = 1;
  358.  
  359.     m_lpUserData = NULL;        // Initialize to no user data
  360.     m_bPreview = FALSE;         // initialize to not preview
  361.     m_bDirect = FALSE;          // initialize to not direct
  362.     m_bDocObject = FALSE;       // initialize to not IPrint
  363.     m_bContinuePrinting = TRUE; // Assume it is OK to print
  364.  
  365.     m_dwFlags = 0;
  366.     m_nOffsetPage = 0;
  367. }
  368.  
  369. CPrintInfo::~CPrintInfo()
  370. {
  371.     if (m_pPD != NULL && m_pPD->m_pd.hDC != NULL)
  372.     {
  373.         ::DeleteDC(m_pPD->m_pd.hDC);
  374.         m_pPD->m_pd.hDC = NULL;
  375.     }
  376.     delete m_pPD;
  377. }
  378.  
  379. /////////////////////////////////////////////////////////////////////////////
  380.