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

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