PRINT.CPP
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:17k
源码类别:

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * PRINT.CPP
  3.  * Patron Chapter 7
  4.  *
  5.  * Implementation of printing functions for both CPatronDoc
  6.  * and CPages classes.  These functions are here to keep clutter
  7.  * down in document.cpp and pages.cpp.
  8.  *
  9.  * Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  10.  *
  11.  * Kraig Brockschmidt, Microsoft
  12.  * Internet  :  kraigb@microsoft.com
  13.  * Compuserve:  >INTERNET:kraigb@microsoft.com
  14.  */
  15. #include "patron.h"
  16. static HWND g_hDlgPrint=NULL;
  17. static BOOL g_fCancelPrint=FALSE;
  18. /*
  19.  * CPatronDoc::Print
  20.  *
  21.  * Purpose:
  22.  *  Prints the current document.
  23.  *
  24.  * Parameters:
  25.  *  hWndFrame       HWND of the frame to use for dialog parents.
  26.  *
  27.  * Return Value:
  28.  *  BOOL            TRUE if printing happened, FALSE if it didn't
  29.  *                  start or didn't complete.
  30.  */
  31. BOOL CPatronDoc::Print(HWND hWndFrame)
  32.     {
  33.     PRINTDLG        pd;
  34.     BOOL            fSuccess;
  35.     memset(&pd, 0, sizeof(PRINTDLG));
  36.     pd.lStructSize=sizeof(PRINTDLG);
  37.     pd.hwndOwner  =hWndFrame;
  38.     pd.nCopies    =1;
  39.     pd.nFromPage  =(USHORT)-1;
  40.     pd.nToPage    =(USHORT)-1;
  41.     pd.nMinPage   =1;
  42.     pd.nMaxPage   =m_pPG->NumPagesGet();
  43.     pd.lpfnPrintHook=PrintDlgHook;
  44.     //Get the current document printer settings
  45.     pd.hDevMode=m_pPG->DevModeGet();
  46.     pd.Flags=PD_RETURNDC | PD_ALLPAGES | PD_COLLATE
  47.         | PD_HIDEPRINTTOFILE | PD_NOSELECTION | PD_ENABLEPRINTHOOK;
  48.     if (!PrintDlg(&pd))
  49.         return FALSE;
  50.     if (NULL!=pd.hDevMode)
  51.         GlobalFree(pd.hDevMode);
  52.     if (NULL!=pd.hDevNames)
  53.         GlobalFree(pd.hDevNames);
  54.     //Go do the actual printing.
  55.     fSuccess=m_pPG->Print(pd.hDC, PSZ(IDS_DOCUMENTNAME), pd.Flags
  56.         , pd.nFromPage, pd.nToPage, pd.nCopies);
  57.     if (!fSuccess)
  58.         {
  59.         MessageBox(m_hWnd, PSZ(IDS_PRINTERROR)
  60.             , PSZ(IDS_DOCUMENTCAPTION), MB_OK);
  61.         }
  62.     return fSuccess;
  63.     }
  64. /*
  65.  * CPatronDoc::PrinterSetup
  66.  *
  67.  * Purpose:
  68.  *  Selects a new printer and options for this document.
  69.  *
  70.  * Parameters:
  71.  *  hWndFrame       HWND of the frame to use for dialog parents.
  72.  *  fDefault        BOOL to avoid any dialog and just use the
  73.  *                  default.
  74.  *
  75.  * Return Value:
  76.  *  UINT            Undefined
  77.  */
  78. UINT CPatronDoc::PrinterSetup(HWND hWndFrame, BOOL fDefault)
  79.     {
  80.     PRINTDLG        pd;
  81.     //Attempt to get printer metrics for the default printer.
  82.     memset(&pd, 0, sizeof(PRINTDLG));
  83.     pd.lStructSize=sizeof(PRINTDLG);
  84.     if (fDefault)
  85.         pd.Flags=PD_RETURNDEFAULT;
  86.     else
  87.         {
  88.         pd.hwndOwner=hWndFrame;
  89.         pd.Flags=PD_PRINTSETUP;
  90.         //Get the current document printer settings
  91.         pd.hDevMode=m_pPG->DevModeGet();
  92.         }
  93.     if (!PrintDlg(&pd))
  94.         return FALSE;
  95.     if (!m_pPG->DevModeSet(pd.hDevMode, pd.hDevNames))
  96.         {
  97.         GlobalFree(pd.hDevNames);
  98.         GlobalFree(pd.hDevMode);
  99.         return FALSE;
  100.         }
  101.     FDirtySet(TRUE);
  102.     return 1;
  103.     }
  104. /*
  105.  * PrintDlgHook
  106.  *
  107.  * Purpose:
  108.  *  Callback hook for the Print Dialog so we can hide the Setup
  109.  *  button.  Patron only allows Setup before anything exists on
  110.  *  the page, and is not written to handle setup at Print time.
  111.  */
  112. UINT CALLBACK PrintDlgHook(HWND hDlg, UINT iMsg, WPARAM wParam
  113.     , LPARAM lParam)
  114.     {
  115.     if (WM_INITDIALOG==iMsg)
  116.         {
  117.         HWND        hWnd;
  118.         hWnd=GetDlgItem(hDlg, psh1);
  119.         ShowWindow(hWnd, SW_HIDE);
  120.         return TRUE;
  121.         }
  122.     return FALSE;
  123.     }
  124. /*
  125.  * CPages::DevModeSet
  126.  *
  127.  * Purpose:
  128.  *  Provides the Pages with the current printer information.
  129.  *
  130.  * Parameters:
  131.  *  hDevMode        HGLOBAL to the memory containing the DEVMODE.
  132.  *                  This function assumes responsibility for this
  133.  *                  handle.
  134.  *  hDevNames       HGLOBAL providing the driver name and device
  135.  *                  name from which we can create a DC for
  136.  *                  information.
  137.  *
  138.  * Return Value:
  139.  *  BOOL            TRUE if we could accept this configuration,
  140.  *                  FALSE otherwise.  If we return TRUE we also
  141.  *                  delete the old memory we hold.
  142.  */
  143. BOOL CPages::DevModeSet(HGLOBAL hDevMode, HGLOBAL hDevNames)
  144.     {
  145.     LPDEVNAMES      pdn;
  146.     LPTSTR          psz;
  147.     //CHAPTER7MOD
  148.     HGLOBAL         hMem;
  149.     PDEVICECONFIG   pdc;
  150.     LPDEVMODE       pdm;
  151.     LPSTREAM        pIStream;
  152.     HRESULT         hr;
  153.     ULONG           cbDevMode, cbWrite;
  154.     BOOL            fRet=FALSE;
  155.     if (NULL==hDevMode || NULL==hDevNames)
  156.         return FALSE;
  157.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  158.         | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  159.     if (FAILED(hr))
  160.         return FALSE;
  161.     /*
  162.      * DEVMODE is variable length--total length in hDevMode, so the
  163.      * amount to write is that plus string space.  We subtract
  164.      * sizeof(DEVMODE) as that is already included from GlobalSize.
  165.      */
  166.     cbDevMode=GlobalSize(hDevMode);
  167.     cbWrite=cbDevMode+sizeof(DEVICECONFIG)-sizeof(DEVMODE);
  168.     hMem=GlobalAlloc(GHND, cbWrite);
  169.     if (NULL==hMem)
  170.         {
  171.         pIStream->Release();
  172.         return FALSE;
  173.         }
  174.     pdc=(PDEVICECONFIG)GlobalLock(hMem);    //This always works
  175.     pdm=(LPDEVMODE)GlobalLock(hDevMode);    //This might not
  176.     if (NULL!=pdm)
  177.         {
  178.         pdc->cb=cbWrite;
  179.         pdc->cbDevMode=cbDevMode;
  180.         memcpy(&pdc->dm, pdm, (int)cbDevMode);
  181.         GlobalUnlock(hDevMode);
  182.         psz=(LPTSTR)GlobalLock(hDevNames);
  183.         if (NULL!=psz)
  184.             {
  185.             pdn=(LPDEVNAMES)psz;
  186.             lstrcpy(pdc->szDriver, psz+pdn->wDriverOffset);
  187.             lstrcpy(pdc->szDevice, psz+pdn->wDeviceOffset);
  188.             lstrcpy(pdc->szPort,   psz+pdn->wOutputOffset);
  189.             pIStream->Write(pdc, cbWrite, &cbWrite);
  190.             GlobalUnlock(hDevNames);
  191.             fRet=TRUE;
  192.             }
  193.         }
  194.     GlobalUnlock(hMem);
  195.     GlobalFree(hMem);
  196.     pIStream->Release();
  197.     if (!fRet)
  198.         return FALSE;
  199.     GlobalFree(hDevNames);
  200.     GlobalFree(hDevMode);
  201.     //End CHAPTER7MOD
  202.     return ConfigureForDevice();
  203.     }
  204. /*
  205.  * CPages::DevModeGet
  206.  *
  207.  * Purpose:
  208.  *  Retrieves a copy of the current DEVMODE structure for this
  209.  *  Pages window.  The caller is responsible for this memory.
  210.  *
  211.  * Parameters:
  212.  *  None
  213.  *
  214.  * Return Value:
  215.  *  HGLOBAL         Handle to the memory containing the DEVMODE
  216.  *                  structure.
  217.  */
  218. HGLOBAL CPages::DevModeGet(void)
  219.     {
  220.     //CHAPTER7MOD
  221.     HGLOBAL         hMem;
  222.     LPVOID          pv;
  223.     ULONG           cbDevMode, cbRead;
  224.     LARGE_INTEGER   li;
  225.     LPSTREAM        pIStream;
  226.     HRESULT         hr;
  227.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  228.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  229.     if (FAILED(hr))
  230.         return FALSE;
  231.     //Read how much to allocate for the DEVMODE structure
  232.     LISet32(li, CBSEEKOFFSETCBDEVMODE);
  233.     pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  234.     pIStream->Read(&cbDevMode, sizeof(ULONG), &cbRead);
  235.     hMem=GlobalAlloc(GHND, cbDevMode);
  236.     if (NULL!=hMem)
  237.         {
  238.         pv=(LPVOID)GlobalLock(hMem);
  239.         pIStream->Read(pv, cbDevMode, &cbRead);
  240.         GlobalUnlock(hMem);
  241.         }
  242.     pIStream->Release();
  243.     //End CHAPTER7MOD
  244.     return hMem;
  245.     }
  246. /*
  247.  * CPages::ConfigureForDevice
  248.  *
  249.  * Purpose:
  250.  *  Recalculates our drawing configuration based on the contents of
  251.  *  an hDC.  If no HDC is given we use the contents of our DevMode
  252.  *  stream.
  253.  *
  254.  * Parameters:
  255.  *  None
  256.  *
  257.  * Return Value:
  258.  *  BOOL            TRUE if successful, FALSE otherwise.
  259.  */
  260. BOOL CPages::ConfigureForDevice(void)
  261.     {
  262.     POINT           ptOffset, ptPaper;
  263.     RECT            rc;
  264.     HDC             hDC;
  265.     CHourglass      hg;
  266.     //CHAPTER7MOD
  267.     HGLOBAL         hMem;
  268.     PDEVICECONFIG   pdc;
  269.     HRESULT         hr;
  270.     LARGE_INTEGER   li;
  271.     LPSTREAM        pIStream;
  272.     ULONG           cb, cbRead;
  273.     //Read the DEVMODE and driver names from the header stream.
  274.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  275.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  276.     if (FAILED(hr))
  277.         return FALSE;
  278.     //Read size of structure including variable portion of DEVMODE
  279.     pIStream->Read(&cb, sizeof(DWORD), &cbRead);
  280.     hMem=GlobalAlloc(GHND, cb);
  281.     if (NULL==hMem)
  282.         {
  283.         pIStream->Release();
  284.         return FALSE;
  285.         }
  286.     //Now get the real information.
  287.     pdc=(PDEVICECONFIG)GlobalLock(hMem);
  288.     LISet32(li, 0);
  289.     pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  290.     pIStream->Read(pdc, cb, &cbRead);
  291.     pIStream->Release();
  292.     //Get the DC then configure
  293.     hDC=CreateIC(pdc->szDriver, pdc->szDevice, pdc->szPort, &pdc->dm);
  294.     //Got what we want, clean up the memory.
  295.     GlobalUnlock(hMem);
  296.     GlobalFree(hMem);
  297.     //End CHAPTER7MOD
  298.     if (NULL==hDC)
  299.         return FALSE;
  300.     //Get usable page dimensions:  already sensitive to orientation
  301.     m_cx=GetDeviceCaps(hDC, HORZSIZE)*10-16; //*10: mm to LOMETRIC
  302.     m_cy=GetDeviceCaps(hDC, VERTSIZE)*10-16; //-16: for driver bugs.
  303.     //Calculate the printer-limited margins on sides in LOMETRIC.
  304.     Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, &ptOffset);
  305.     Escape(hDC, GETPHYSPAGESIZE,   NULL, NULL, &ptPaper);
  306.     SetRect(&rc, ptOffset.x, ptOffset.y, ptPaper.x, ptPaper.y);
  307.     SetMapMode(hDC, MM_LOMETRIC);
  308.     RectConvertMappings(&rc, hDC, FALSE);
  309.     //Left and top margins are the printing offset.
  310.     m_xMarginLeft= rc.left+8;   //+8 to match -16 above
  311.     m_yMarginTop =-rc.top+8;    //LOMETRIC makes this negative.
  312.     //Right is (paper width)-(usable width)-(left margin)
  313.     m_xMarginRight =rc.right-m_cx-m_xMarginLeft;
  314.     //Bottom is (paper height)-(usable height)-(top margin)+1
  315.     m_yMarginBottom=-rc.bottom-m_cy-m_yMarginTop+1;
  316.     UpdateScrollRanges();
  317.     DeleteDC(hDC);
  318.     return TRUE;
  319.     }
  320. /*
  321.  * CPages::Print
  322.  *
  323.  * Purpose:
  324.  *  Prints a specified range of pages to a given hDC.  Repeats for
  325.  *  a given number of copies.
  326.  *
  327.  * Parameters:
  328.  *  hDC             HDC to which we print.
  329.  *  pszDoc          LPTSTR providing the document name.
  330.  *  dwFlags         DWORD flags from PrintDlg
  331.  *  iPageStart      UINT starting page index (one based)
  332.  *  iPageEnd        UINT ending page index (one based).  Includes
  333.  *                  this page.
  334.  *  cCopies         UINT number of copies to print.  If PD_COLLATE
  335.  *                  in dwFlags is set, we print multiple copies of
  336.  *                  each page as we cycle through.  Otherwise we
  337.  *                  cycle multiple times.
  338.  *
  339.  * Return Value:
  340.  *  None
  341.  */
  342. BOOL CPages::Print(HDC hDC, LPTSTR pszDoc, DWORD dwFlags
  343.     , UINT iPageStart, UINT iPageEnd, UINT cCopies)
  344.     {
  345.     BOOL        fError=FALSE;
  346.     int         iPage, iPageInc;
  347.     int         iUserPage, cPages;
  348.     UINT        iRepeat, cRepeat;
  349.     UINT        iCycle, cCycles;
  350.     UINT        iPageHold=m_iPageCur;
  351.     HWND        hWndT, hWndTop=NULL;
  352.     DOCINFO     di;
  353.     PCDocument  pDoc;
  354.     //Validate hDC and page ranges
  355.     if (NULL==hDC)
  356.         return FALSE;
  357.     if ((PD_PAGENUMS & dwFlags))
  358.         {
  359.         if (-1==iPageStart)
  360.             iPageStart=0;
  361.         else
  362.             iPageStart--;   //Switch to zero offset.
  363.         if (-1==iPageEnd)
  364.             iPageEnd=m_cPages-1;
  365.         else
  366.             iPageEnd--;     //Switch to zero offset.
  367.         }
  368.     else //Can't test PD_ALLPAGES with & since it's defined as 0L
  369.         {
  370.         iPageStart=0;
  371.         iPageEnd=m_cPages-1;
  372.         }
  373.     //Arrange cycles and repeats depending on cCopies and collating
  374.     if (PD_COLLATE & dwFlags)
  375.         {
  376.         cCycles=cCopies;
  377.         cRepeat=1;
  378.         }
  379.     else
  380.         {
  381.         cCycles=1;
  382.         cRepeat=cCopies;
  383.         }
  384.     //Disable the frame window to prevent reentrancy while printing.
  385.     hWndT=GetParent(m_hWnd);
  386.     pDoc=(PCDocument)SendMessage(hWndT, DOCM_PDOCUMENT, 0, 0L);
  387.     if (NULL!=pDoc)
  388.         {
  389.         PCFrame pFR;
  390.         pFR=pDoc->FrameGet();
  391.         hWndTop=pFR->Window();
  392.         EnableWindow(hWndTop, FALSE);
  393.         }
  394.     SetAbortProc(hDC, AbortProc);
  395.     g_fCancelPrint=FALSE;
  396.     //If these don't work then we'll just live without a dialog.
  397.     g_hDlgPrint=CreateDialog(m_hInst, MAKEINTRESOURCE(IDD_PRINTING)
  398.         , hWndTop, PrintDlgProc);
  399.     //Increment for either direction.
  400.     iPageInc=(iPageStart > iPageEnd) ? -1 : 1;
  401.     //Initial entries in dialog box.
  402.     cPages=1+((int)(iPageEnd-iPageStart)*iPageInc);
  403.     SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE, 1, (LPARAM)cPages);
  404.     SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, 1, (LPARAM)cRepeat);
  405.     di.cbSize=sizeof(DOCINFO);
  406.     di.lpszDocName=pszDoc;
  407.     di.lpszOutput=NULL;
  408.     if (StartDoc(hDC, &di) > 0)
  409.         {
  410.         /*
  411.          * Iterate over the pages, repeating each page depending on
  412.          * the copies we want and if we have collate enabled.
  413.          */
  414.         for (iCycle=1; iCycle <= cCycles; iCycle++)
  415.             {
  416.             if (PD_COLLATE & dwFlags)
  417.                 {
  418.                 SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, iCycle
  419.                     , (LPARAM)cCycles);
  420.                 }
  421.             //iPageInc controls direction
  422.             for (iPage=iPageStart; ; iPage+=iPageInc)
  423.                 {
  424.                 iUserPage=1+((iPage-(int)iPageStart)*iPageInc);
  425.                 SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE
  426.                     , iUserPage, (LPARAM)cPages);
  427.                 m_iPageCur=iPage;   //We restore this later.
  428.                 for (iRepeat=1; iRepeat <= cRepeat; iRepeat++)
  429.                     {
  430.                     if (!(PD_COLLATE & dwFlags))
  431.                         {
  432.                         SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE
  433.                             , iRepeat, (LPARAM)cRepeat);
  434.                         }
  435.                     StartPage(hDC);
  436.                     Draw(hDC, TRUE, TRUE);
  437.                     if (EndPage(hDC) < 0)
  438.                         fError=TRUE;
  439.                     if (fError || g_fCancelPrint)
  440.                         break;
  441.                     }
  442.                 if (fError || g_fCancelPrint)
  443.                     break;
  444.                 //If we just printed the last page, time to quit.
  445.                 if (iPage==(int)iPageEnd)
  446.                     break;
  447.                 }
  448.             if (fError || g_fCancelPrint)
  449.                 break;
  450.             }
  451.         if (!fError)
  452.             EndDoc(hDC);
  453.         else
  454.             AbortDoc(hDC);
  455.         }
  456.     else
  457.         fError=TRUE;
  458.     //Set the page back to what it was before all this started.
  459.     m_iPageCur=iPageHold;
  460.     EnableWindow(hWndTop, TRUE);
  461.     SetFocus(hWndTop);
  462.     DestroyWindow(g_hDlgPrint);
  463.     DeleteDC(hDC);
  464.     return !fError;
  465.     }
  466. /*
  467.  * AbortProc
  468.  *
  469.  * Purpose:
  470.  *  Abort procedure for printing the pages.
  471.  *
  472.  * Parameters:
  473.  *  hDC             HDC on which printing is happening.
  474.  *  iErr            int error code.
  475.  *
  476.  * Return Value:
  477.  *  BOOL            TRUE to continue the print job, FALSE otherwise.
  478.  */
  479. BOOL APIENTRY AbortProc(HDC hDC, int iErr)
  480.     {
  481.     MSG     msg;
  482.     while (!g_fCancelPrint
  483.         && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  484.         {
  485.         if (NULL==g_hDlgPrint
  486.             || !IsDialogMessage(g_hDlgPrint, &msg))
  487.             {
  488.             TranslateMessage(&msg);
  489.             DispatchMessage(&msg);
  490.             }
  491.         }
  492.     return !g_fCancelPrint;
  493.     }
  494. /*
  495.  * PrintDlgProc
  496.  *
  497.  * Purpose:
  498.  *  Modeless dialog procedure for the dialog displayed while Patron
  499.  *  is printing pages.
  500.  */
  501. BOOL APIENTRY PrintDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam
  502.     , LPARAM lParam)
  503.     {
  504.     TCHAR           szFormat[40];
  505.     TCHAR           szOutput[80];
  506.     switch (iMsg)
  507.         {
  508.         case WM_INITDIALOG:
  509.             EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE
  510.                 , MF_GRAYED);
  511.             return TRUE;
  512.         case WM_COMMAND:
  513.             //Cancel button was pressed.
  514.             g_fCancelPrint=TRUE;
  515.             ShowWindow(hDlg, SW_HIDE);
  516.             return TRUE;
  517.         case PRINTM_PAGEUPDATE:
  518.             GetDlgItemText(hDlg, ID_PAGESTRING, szFormat
  519.                 , sizeof(szFormat));
  520.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  521.             SetDlgItemText(hDlg, ID_CURRENTPAGE, szOutput);
  522.             return TRUE;
  523.         case PRINTM_COPYUPDATE:
  524.             GetDlgItemText(hDlg, ID_COPYSTRING, szFormat
  525.                 , sizeof(szFormat));
  526.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  527.             SetDlgItemText(hDlg, ID_CURRENTCOPY, szOutput);
  528.             return TRUE;
  529.         }
  530.     return FALSE;
  531.     }