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

Windows编程

开发平台:

Visual C++

  1. /*
  2.  * PRINT.CPP
  3.  * Patron Chapter 12
  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. //CHAPTER12MOD
  125. /*
  126.  * CPatronDoc::FQueryPrinterSetup
  127.  *
  128.  * Purpose:
  129.  *  Returns whether or not the Printer Setup menu item can be
  130.  *  enabled.  Once you create a tenant in any page, Printer Setup
  131.  *  is voided simply to keep this sample simple, that is, we don't
  132.  *  have to worry about reorganizing potentially large amounts
  133.  *  of layout after we start plopping down objects.
  134.  *
  135.  * Parameters:
  136.  *  None
  137.  *
  138.  * Return Value:
  139.  *  BOOL            TRUE to enable the menu, FALSE otherwise.
  140.  */
  141. BOOL CPatronDoc::FQueryPrinterSetup(void)
  142.     {
  143.     return m_fPrintSetup;
  144.     }
  145. //End CHAPTER12MOD
  146. /*
  147.  * CPages::DevModeSet
  148.  *
  149.  * Purpose:
  150.  *  Provides the Pages with the current printer information.
  151.  *
  152.  * Parameters:
  153.  *  hDevMode        HGLOBAL to the memory containing the DEVMODE.
  154.  *                  This function assumes responsibility for this
  155.  *                  handle.
  156.  *  hDevNames       HGLOBAL providing the driver name and device
  157.  *                  name from which we can create a DC for
  158.  *                  information.
  159.  *
  160.  * Return Value:
  161.  *  BOOL            TRUE if we could accept this configuration,
  162.  *                  FALSE otherwise.  If we return TRUE we also
  163.  *                  delete the old memory we hold.
  164.  */
  165. BOOL CPages::DevModeSet(HGLOBAL hDevMode, HGLOBAL hDevNames)
  166.     {
  167.     LPDEVNAMES      pdn;
  168.     LPTSTR          psz;
  169.     HGLOBAL         hMem;
  170.     PDEVICECONFIG   pdc;
  171.     LPDEVMODE       pdm;
  172.     LPSTREAM        pIStream;
  173.     HRESULT         hr;
  174.     ULONG           cbDevMode, cbWrite;
  175.     BOOL            fRet=FALSE;
  176.     if (NULL==hDevMode || NULL==hDevNames)
  177.         return FALSE;
  178.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  179.         | STGM_WRITE | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  180.     if (FAILED(hr))
  181.         return FALSE;
  182.     /*
  183.      * DEVMODE is variable length--total length in hDevMode, so the
  184.      * amount to write is that plus string space.  We subtract
  185.      * sizeof(DEVMODE) as that is already included from GlobalSize.
  186.      */
  187.     cbDevMode=GlobalSize(hDevMode);
  188.     cbWrite=cbDevMode+sizeof(DEVICECONFIG)-sizeof(DEVMODE);
  189.     hMem=GlobalAlloc(GHND, cbWrite);
  190.     if (NULL==hMem)
  191.         {
  192.         pIStream->Release();
  193.         return FALSE;
  194.         }
  195.     pdc=(PDEVICECONFIG)GlobalLock(hMem);    //This always works
  196.     pdm=(LPDEVMODE)GlobalLock(hDevMode);    //This might not
  197.     if (NULL!=pdm)
  198.         {
  199.         pdc->cb=cbWrite;
  200.         pdc->cbDevMode=cbDevMode;
  201.         memcpy(&pdc->dm, pdm, (int)cbDevMode);
  202.         GlobalUnlock(hDevMode);
  203.         psz=(LPTSTR)GlobalLock(hDevNames);
  204.         if (NULL!=psz)
  205.             {
  206.             pdn=(LPDEVNAMES)psz;
  207.             lstrcpy(pdc->szDriver, psz+pdn->wDriverOffset);
  208.             lstrcpy(pdc->szDevice, psz+pdn->wDeviceOffset);
  209.             lstrcpy(pdc->szPort,   psz+pdn->wOutputOffset);
  210.             pIStream->Write(pdc, cbWrite, &cbWrite);
  211.             GlobalUnlock(hDevNames);
  212.             fRet=TRUE;
  213.             }
  214.         }
  215.     GlobalUnlock(hMem);
  216.     GlobalFree(hMem);
  217.     pIStream->Release();
  218.     if (!fRet)
  219.         return FALSE;
  220.     GlobalFree(hDevNames);
  221.     GlobalFree(hDevMode);
  222.     return ConfigureForDevice();
  223.     }
  224. /*
  225.  * CPages::DevModeGet
  226.  *
  227.  * Purpose:
  228.  *  Retrieves a copy of the current DEVMODE structure for this
  229.  *  Pages window.  The caller is responsible for this memory.
  230.  *
  231.  * Parameters:
  232.  *  None
  233.  *
  234.  * Return Value:
  235.  *  HGLOBAL         Handle to the memory containing the DEVMODE
  236.  *                  structure.
  237.  */
  238. HGLOBAL CPages::DevModeGet(void)
  239.     {
  240.     HGLOBAL         hMem;
  241.     LPVOID          pv;
  242.     ULONG           cbDevMode, cbRead;
  243.     LARGE_INTEGER   li;
  244.     LPSTREAM        pIStream;
  245.     HRESULT         hr;
  246.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  247.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  248.     if (FAILED(hr))
  249.         return FALSE;
  250.     //Read how much to allocate for the DEVMODE structure
  251.     LISet32(li, CBSEEKOFFSETCBDEVMODE);
  252.     pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  253.     pIStream->Read(&cbDevMode, sizeof(ULONG), &cbRead);
  254.     hMem=GlobalAlloc(GHND, cbDevMode);
  255.     if (NULL!=hMem)
  256.         {
  257.         pv=(LPVOID)GlobalLock(hMem);
  258.         pIStream->Read(pv, cbDevMode, &cbRead);
  259.         GlobalUnlock(hMem);
  260.         }
  261.     pIStream->Release();
  262.     return hMem;
  263.     }
  264. //CHAPTER12MOD
  265. /*
  266.  * CPages::DevReadConfig
  267.  *
  268.  * Purpose:
  269.  *  Public function to read the current device configuration and
  270.  *  optionally return an information context for it.
  271.  *
  272.  *
  273.  * Parameters:
  274.  *  ppcd            PCOMBINEDEVICE * in which to return a pointer
  275.  *                  to an allocated structure that has all the
  276.  *                  device information we want.  Ignored if NULL.
  277.  *                  This is allocated with the task allocator.
  278.  *  phDC            HDC * in which to return the information
  279.  *                  context.  If NULL, no IC is created.  Caller
  280.  *                  becomes responsible for the returned IC.
  281.  *
  282.  * Return Value:
  283.  *  BOOL            TRUE if successful, FALSE otherwise.
  284.  */
  285. BOOL CPages::DevReadConfig(PCOMBINEDEVICE *ppcd, HDC *phDC)
  286.     {
  287.     HRESULT         hr;
  288.     LPSTREAM        pIStream;
  289.     LPMALLOC        pIMalloc;
  290.     PCOMBINEDEVICE  pcd;
  291.     ULONG           cb, cbRead;
  292.     LARGE_INTEGER   li;
  293.     hr=m_pIStorage->OpenStream(SZSTREAMDEVICECONFIG, 0, STGM_DIRECT
  294.         | STGM_READ | STGM_SHARE_EXCLUSIVE, 0, &pIStream);
  295.     if (FAILED(hr))
  296.         return FALSE;
  297.     /*
  298.      * Allocate the COMBINEDEVICE structure including the variable
  299.      * information past the DEVMODE part.
  300.      */
  301.     hr=CoGetMalloc(MEMCTX_TASK, &pIMalloc);
  302.     if (FAILED(hr))
  303.         {
  304.         pIStream->Release();
  305.         return FALSE;
  306.         }
  307.     /*
  308.      * Read size of the DEVICECONFIG structure including variable
  309.      * portion of DEVMODE.  We need to load all this information
  310.      * for CreateIC.  To this size we'll add the size of
  311.      * DVTARGETDEVICE in order to allocate a COMBINEDEVICE.
  312.      */
  313.     pIStream->Read(&cb, sizeof(DWORD), &cbRead);
  314.     pcd=(PCOMBINEDEVICE)pIMalloc->Alloc(cb+sizeof(DVTARGETDEVICE));
  315.     if (NULL==pcd)
  316.         {
  317.         pIMalloc->Release();
  318.         pIStream->Release();
  319.         return FALSE;
  320.         }
  321.     //Now get the real information.
  322.     LISet32(li, 0);
  323.     pIStream->Seek(li, STREAM_SEEK_SET, NULL);
  324.     pIStream->Read(&(pcd->dc), cb, &cbRead);
  325.     pIStream->Release();
  326.     /*
  327.      * If requested, complete the DVTARGETDEVICE structure in
  328.      * pcd and store pcd in *ppcd for return.
  329.      */
  330.     if (NULL!=ppcd)
  331.         {
  332.         WORD    cb=sizeof(DVTARGETDEVICE);
  333.         pcd->td.tdSize=cb;
  334.         pcd->td.tdExtDevmodeOffset=cb;
  335.         pcd->td.tdDriverNameOffset=cb+sizeof(DEVMODE);
  336.         pcd->td.tdDeviceNameOffset=cb+sizeof(DEVMODE)
  337.             +(CCHDEVICENAME*sizeof(TCHAR));
  338.         pcd->td.tdPortNameOffset  =cb+sizeof(DEVMODE)
  339.             +(CCHDEVICENAME*2*sizeof(TCHAR));
  340.         *ppcd=pcd;
  341.         }
  342.     //Create an IC if requested.
  343.     if (NULL!=phDC)
  344.         {
  345.         //Get the DC then configure
  346.         *phDC=CreateIC(pcd->dc.szDriver, pcd->dc.szDevice
  347.             , pcd->dc.szPort, &(pcd->dc.dm));
  348.         if (NULL==*phDC)
  349.             return FALSE;
  350.         }
  351.     //pcd is a temporary allocation in this case
  352.     if (NULL==ppcd)
  353.         pIMalloc->Free(pcd);
  354.     pIMalloc->Release();
  355.     return (NULL!=*phDC);
  356.     }
  357. //End CHAPTER12MOD
  358. /*
  359.  * CPages::ConfigureForDevice
  360.  *
  361.  * Purpose:
  362.  *  Recalculates our drawing configuration based on the contents of
  363.  *  an hDC.  If no HDC is given we use the contents of our DevMode
  364.  *  stream.
  365.  *
  366.  * Parameters:
  367.  *  None
  368.  *
  369.  * Return Value:
  370.  *  BOOL            TRUE if successful, FALSE otherwise.
  371.  */
  372. BOOL CPages::ConfigureForDevice(void)
  373.     {
  374.     POINT           ptOffset, ptPaper;
  375.     RECT            rc;
  376.     HDC             hDC;
  377.     CHourglass      hg;
  378.     //CHAPTER12MOD
  379.     if (!DevReadConfig(NULL, &hDC))
  380.         return FALSE;
  381.     //End CHAPTER12MOD
  382.     //Get usable page dimensions:  already sensitive to orientation
  383.     m_cx=GetDeviceCaps(hDC, HORZSIZE)*10-16; //*10: mm to LOMETRIC
  384.     m_cy=GetDeviceCaps(hDC, VERTSIZE)*10-16; //-16: for driver bugs.
  385.     //Calculate the printer-limited margins on sides in LOMETRIC.
  386.     Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, &ptOffset);
  387.     Escape(hDC, GETPHYSPAGESIZE,   NULL, NULL, &ptPaper);
  388.     SetRect(&rc, ptOffset.x, ptOffset.y, ptPaper.x, ptPaper.y);
  389.     SetMapMode(hDC, MM_LOMETRIC);
  390.     RectConvertMappings(&rc, hDC, FALSE);
  391.     //Left and top margins are the printing offset.
  392.     m_xMarginLeft= rc.left+8;   //+8 to match -16 above
  393.     m_yMarginTop =-rc.top+8;    //LOMETRIC makes this negative.
  394.     //Right is (paper width)-(usable width)-(left margin)
  395.     m_xMarginRight =rc.right-m_cx-m_xMarginLeft;
  396.     //Bottom is (paper height)-(usable height)-(top margin)+1
  397.     m_yMarginBottom=-rc.bottom-m_cy-m_yMarginTop+1;
  398.     UpdateScrollRanges();
  399.     DeleteDC(hDC);
  400.     return TRUE;
  401.     }
  402. /*
  403.  * CPages::Print
  404.  *
  405.  * Purpose:
  406.  *  Prints a specified range of pages to a given hDC.  Repeats for
  407.  *  a given number of copies.
  408.  *
  409.  * Parameters:
  410.  *  hDC             HDC to which we print.
  411.  *  pszDoc          LPTSTR providing the document name.
  412.  *  dwFlags         DWORD flags from PrintDlg
  413.  *  iPageStart      UINT starting page index (one based)
  414.  *  iPageEnd        UINT ending page index (one based).  Includes
  415.  *                  this page.
  416.  *  cCopies         UINT number of copies to print.  If PD_COLLATE
  417.  *                  in dwFlags is set, we print multiple copies of
  418.  *                  each page as we cycle through.  Otherwise we
  419.  *                  cycle multiple times.
  420.  *
  421.  * Return Value:
  422.  *  None
  423.  */
  424. BOOL CPages::Print(HDC hDC, LPTSTR pszDoc, DWORD dwFlags
  425.     , UINT iPageStart, UINT iPageEnd, UINT cCopies)
  426.     {
  427.     BOOL        fError=FALSE;
  428.     int         iPage, iPageInc;
  429.     int         iUserPage, cPages;
  430.     UINT        iRepeat, cRepeat;
  431.     UINT        iCycle, cCycles;
  432.     UINT        iPageHold=m_iPageCur;
  433.     HWND        hWndT, hWndTop=NULL;
  434.     DOCINFO     di;
  435.     PCDocument  pDoc;
  436.     //Validate hDC and page ranges
  437.     if (NULL==hDC)
  438.         return FALSE;
  439.     if ((PD_PAGENUMS & dwFlags))
  440.         {
  441.         if (-1==iPageStart)
  442.             iPageStart=0;
  443.         else
  444.             iPageStart--;   //Switch to zero offset.
  445.         if (-1==iPageEnd)
  446.             iPageEnd=m_cPages-1;
  447.         else
  448.             iPageEnd--;     //Switch to zero offset.
  449.         }
  450.     else //Can't test PD_ALLPAGES with & since it's defined as 0L
  451.         {
  452.         iPageStart=0;
  453.         iPageEnd=m_cPages-1;
  454.         }
  455.     //Arrange cycles and repeats depending on cCopies and collating
  456.     if (PD_COLLATE & dwFlags)
  457.         {
  458.         cCycles=cCopies;
  459.         cRepeat=1;
  460.         }
  461.     else
  462.         {
  463.         cCycles=1;
  464.         cRepeat=cCopies;
  465.         }
  466.     //Disable the frame window to prevent reentrancy while printing.
  467.     hWndT=GetParent(m_hWnd);
  468.     pDoc=(PCDocument)SendMessage(hWndT, DOCM_PDOCUMENT, 0, 0L);
  469.     if (NULL!=pDoc)
  470.         {
  471.         PCFrame pFR;
  472.         pFR=pDoc->FrameGet();
  473.         hWndTop=pFR->Window();
  474.         EnableWindow(hWndTop, FALSE);
  475.         }
  476.     SetAbortProc(hDC, AbortProc);
  477.     g_fCancelPrint=FALSE;
  478.     //If these don't work then we'll just live without a dialog.
  479.     g_hDlgPrint=CreateDialog(m_hInst, MAKEINTRESOURCE(IDD_PRINTING)
  480.         , hWndTop, PrintDlgProc);
  481.     //Increment for either direction.
  482.     iPageInc=(iPageStart > iPageEnd) ? -1 : 1;
  483.     //Initial entries in dialog box.
  484.     cPages=1+((int)(iPageEnd-iPageStart)*iPageInc);
  485.     SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE, 1, (LPARAM)cPages);
  486.     SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, 1, (LPARAM)cRepeat);
  487.     di.cbSize=sizeof(DOCINFO);
  488.     di.lpszDocName=pszDoc;
  489.     di.lpszOutput=NULL;
  490.     if (StartDoc(hDC, &di) > 0)
  491.         {
  492.         /*
  493.          * Iterate over the pages, repeating each page depending on
  494.          * the copies we want and if we have collate enabled.
  495.          */
  496.         for (iCycle=1; iCycle <= cCycles; iCycle++)
  497.             {
  498.             if (PD_COLLATE & dwFlags)
  499.                 {
  500.                 SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, iCycle
  501.                     , (LPARAM)cCycles);
  502.                 }
  503.             //iPageInc controls direction
  504.             for (iPage=iPageStart; ; iPage+=iPageInc)
  505.                 {
  506.                 iUserPage=1+((iPage-(int)iPageStart)*iPageInc);
  507.                 SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE
  508.                     , iUserPage, (LPARAM)cPages);
  509.                 m_iPageCur=iPage;   //We restore this later.
  510.                 for (iRepeat=1; iRepeat <= cRepeat; iRepeat++)
  511.                     {
  512.                     if (!(PD_COLLATE & dwFlags))
  513.                         {
  514.                         SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE
  515.                             , iRepeat, (LPARAM)cRepeat);
  516.                         }
  517.                     StartPage(hDC);
  518.                     Draw(hDC, TRUE, TRUE);
  519.                     if (EndPage(hDC) < 0)
  520.                         fError=TRUE;
  521.                     if (fError || g_fCancelPrint)
  522.                         break;
  523.                     }
  524.                 if (fError || g_fCancelPrint)
  525.                     break;
  526.                 //If we just printed the last page, time to quit.
  527.                 if (iPage==(int)iPageEnd)
  528.                     break;
  529.                 }
  530.             if (fError || g_fCancelPrint)
  531.                 break;
  532.             }
  533.         if (!fError)
  534.             EndDoc(hDC);
  535.         else
  536.             AbortDoc(hDC);
  537.         }
  538.     else
  539.         fError=TRUE;
  540.     //Set the page back to what it was before all this started.
  541.     m_iPageCur=iPageHold;
  542.     EnableWindow(hWndTop, TRUE);
  543.     SetFocus(hWndTop);
  544.     DestroyWindow(g_hDlgPrint);
  545.     DeleteDC(hDC);
  546.     return !fError;
  547.     }
  548. /*
  549.  * AbortProc
  550.  *
  551.  * Purpose:
  552.  *  Abort procedure for printing the pages.
  553.  *
  554.  * Parameters:
  555.  *  hDC             HDC on which printing is happening.
  556.  *  iErr            int error code.
  557.  *
  558.  * Return Value:
  559.  *  BOOL            TRUE to continue the print job, FALSE otherwise.
  560.  */
  561. BOOL APIENTRY AbortProc(HDC hDC, int iErr)
  562.     {
  563.     MSG     msg;
  564.     while (!g_fCancelPrint
  565.         && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  566.         {
  567.         if (NULL==g_hDlgPrint
  568.             || !IsDialogMessage(g_hDlgPrint, &msg))
  569.             {
  570.             TranslateMessage(&msg);
  571.             DispatchMessage(&msg);
  572.             }
  573.         }
  574.     return !g_fCancelPrint;
  575.     }
  576. /*
  577.  * PrintDlgProc
  578.  *
  579.  * Purpose:
  580.  *  Modeless dialog procedure for the dialog displayed while Patron
  581.  *  is printing pages.
  582.  */
  583. BOOL APIENTRY PrintDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam
  584.     , LPARAM lParam)
  585.     {
  586.     TCHAR           szFormat[40];
  587.     TCHAR           szOutput[80];
  588.     switch (iMsg)
  589.         {
  590.         case WM_INITDIALOG:
  591.             EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE
  592.                 , MF_GRAYED);
  593.             return TRUE;
  594.         case WM_COMMAND:
  595.             //Cancel button was pressed.
  596.             g_fCancelPrint=TRUE;
  597.             ShowWindow(hDlg, SW_HIDE);
  598.             return TRUE;
  599.         case PRINTM_PAGEUPDATE:
  600.             GetDlgItemText(hDlg, ID_PAGESTRING, szFormat
  601.                 , sizeof(szFormat));
  602.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  603.             SetDlgItemText(hDlg, ID_CURRENTPAGE, szOutput);
  604.             return TRUE;
  605.         case PRINTM_COPYUPDATE:
  606.             GetDlgItemText(hDlg, ID_COPYSTRING, szFormat
  607.                 , sizeof(szFormat));
  608.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  609.             SetDlgItemText(hDlg, ID_CURRENTCOPY, szOutput);
  610.             return TRUE;
  611.         }
  612.     return FALSE;
  613.     }