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

Windows编程

开发平台:

Visual C++

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