home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / com / inole2 / chap07 / patron / print.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  17KB  |  679 lines

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