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 / chap12 / patron / print.cpp < prev    next >
C/C++ Source or Header  |  1995-05-03  |  20KB  |  779 lines

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