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

  1. /*
  2.  * PRINT.CPP
  3.  * Patron Chapter 1
  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.  
  191.     if (NULL==hDevMode || NULL==hDevNames)
  192.         return FALSE;
  193.  
  194.     psz=(LPTSTR)GlobalLock(hDevNames);
  195.  
  196.     if (NULL==psz)
  197.         return FALSE;
  198.  
  199.     pdn=(LPDEVNAMES)psz;
  200.     lstrcpy(m_szDriver, psz+pdn->wDriverOffset);
  201.     lstrcpy(m_szDevice, psz+pdn->wDeviceOffset);
  202.     lstrcpy(m_szPort,   psz+pdn->wOutputOffset);
  203.     GlobalUnlock(hDevNames);
  204.     GlobalFree(hDevNames);
  205.  
  206.     //Save this new memory and get rid of the old.
  207.     if (NULL!=m_hDevMode)
  208.         GlobalFree(m_hDevMode);
  209.  
  210.     m_hDevMode=hDevMode;
  211.  
  212.     return ConfigureForDevice();
  213.     }
  214.  
  215.  
  216.  
  217.  
  218.  
  219.  
  220.  
  221. /*
  222.  * CPages::DevModeGet
  223.  *
  224.  * Purpose:
  225.  *  Retrieves a copy of the current DEVMODE structure for this
  226.  *  Pages window.  The caller is responsible for this memory.
  227.  *
  228.  * Parameters:
  229.  *  None
  230.  *
  231.  * Return Value:
  232.  *  HGLOBAL         Handle to the memory containing the DEVMODE
  233.  *                  structure.
  234.  */
  235.  
  236. HGLOBAL CPages::DevModeGet(void)
  237.     {
  238.     HGLOBAL     hMem;
  239.     DWORD       cb;
  240.     DWORD       i;
  241.     LPBYTE      pb1, pb2;
  242.  
  243.     cb=GlobalSize(m_hDevMode);
  244.  
  245.     if (0==cb)
  246.         return NULL;
  247.  
  248.     hMem=GlobalAlloc(GHND, cb);
  249.  
  250.     if (NULL==hMem)
  251.         return NULL;
  252.  
  253.     pb1=(LPBYTE)GlobalLock(hMem);
  254.     pb2=(LPBYTE)GlobalLock(m_hDevMode);
  255.  
  256.     //Copy the existing DEVMODE structure
  257.     for (i=0; i < cb; i++)
  258.         *pb1++=*pb2++;
  259.  
  260.     GlobalUnlock(m_hDevMode);
  261.     GlobalUnlock(hMem);
  262.  
  263.     return hMem;
  264.     }
  265.  
  266.  
  267.  
  268.  
  269. /*
  270.  * CPages::ConfigureForDevice
  271.  *
  272.  * Purpose:
  273.  *  Recalculates our drawing configuration based on the contents of
  274.  *  an hDC.  If no HDC is given we use the contents of our DevMode
  275.  *  stream.
  276.  *
  277.  * Parameters:
  278.  *  None
  279.  *
  280.  * Return Value:
  281.  *  BOOL            TRUE if successful, FALSE otherwise.
  282.  */
  283.  
  284. BOOL CPages::ConfigureForDevice(void)
  285.     {
  286.     POINT           ptOffset, ptPaper;
  287.     RECT            rc;
  288.     HDC             hDC;
  289.     LPDEVMODE       pdm;
  290.     CHourglass      hg;     //Shows wait cursor, automatically destroyed
  291.  
  292.     pdm=(LPDEVMODE)GlobalLock(m_hDevMode);
  293.  
  294.     if (NULL==pdm)
  295.         return FALSE;
  296.  
  297.     //Get the DC then configure
  298.     hDC=CreateIC(m_szDriver, m_szDevice, m_szPort, pdm);
  299.  
  300.     GlobalUnlock(m_hDevMode);
  301.  
  302.     if (NULL==hDC)
  303.         return FALSE;
  304.  
  305.     //Get usable page dimensions:  already sensitive to orientation
  306.     m_cx=GetDeviceCaps(hDC, HORZSIZE)*10-16; //*10: mm to LOMETRIC
  307.     m_cy=GetDeviceCaps(hDC, VERTSIZE)*10-16; //-16: for driver bugs.
  308.  
  309.     //Calculate the printer-limited margins on sides in LOMETRIC.
  310.     Escape(hDC, GETPRINTINGOFFSET, NULL, NULL, &ptOffset);
  311.     Escape(hDC, GETPHYSPAGESIZE,   NULL, NULL, &ptPaper);
  312.  
  313.     SetRect(&rc, ptOffset.x, ptOffset.y, ptPaper.x, ptPaper.y);
  314.     SetMapMode(hDC, MM_LOMETRIC);
  315.     RectConvertMappings(&rc, hDC, FALSE);
  316.  
  317.     //Left and top margins are the printing offset.
  318.     m_xMarginLeft= rc.left+8;   //+8 to match -16 above
  319.     m_yMarginTop =-rc.top+8;    //LOMETRIC makes this negative.
  320.  
  321.     //Right is (paper width)-(usable width)-(left margin)
  322.     m_xMarginRight =rc.right-m_cx-m_xMarginLeft;
  323.  
  324.     //Bottom is (paper height)-(usable height)-(top margin)+1
  325.     m_yMarginBottom=-rc.bottom-m_cy-m_yMarginTop+1;
  326.  
  327.     UpdateScrollRanges();
  328.  
  329.     DeleteDC(hDC);
  330.     return TRUE;
  331.     }
  332.  
  333.  
  334.  
  335.  
  336. /*
  337.  * CPages::Print
  338.  *
  339.  * Purpose:
  340.  *  Prints a specified range of pages to a given hDC.  Repeats for
  341.  *  a given number of copies.
  342.  *
  343.  * Parameters:
  344.  *  hDC             HDC to which we print.
  345.  *  pszDoc          LPTSTR providing the document name.
  346.  *  dwFlags         DWORD flags from PrintDlg
  347.  *  iPageStart      UINT starting page index (one based)
  348.  *  iPageEnd        UINT ending page index (one based).  Includes
  349.  *                  this page.
  350.  *  cCopies         UINT number of copies to print.  If PD_COLLATE
  351.  *                  in dwFlags is set, we print multiple copies of
  352.  *                  each page as we cycle through.  Otherwise we
  353.  *                  cycle multiple times.
  354.  *
  355.  * Return Value:
  356.  *  None
  357.  */
  358.  
  359. BOOL CPages::Print(HDC hDC, LPTSTR pszDoc, DWORD dwFlags
  360.     , UINT iPageStart, UINT iPageEnd, UINT cCopies)
  361.     {
  362.     BOOL        fError=FALSE;
  363.     int         iPage, iPageInc;
  364.     int         iUserPage, cPages;
  365.     UINT        iRepeat, cRepeat;
  366.     UINT        iCycle, cCycles;
  367.     UINT        iPageHold=m_iPageCur;
  368.     HWND        hWndT, hWndTop=NULL;
  369.     DOCINFO     di;
  370.     PCDocument  pDoc;
  371.  
  372.     //Validate hDC and page ranges
  373.     if (NULL==hDC)
  374.         return FALSE;
  375.  
  376.     if ((PD_PAGENUMS & dwFlags))
  377.         {
  378.         if (-1==iPageStart)
  379.             iPageStart=0;
  380.         else
  381.             iPageStart--;   //Switch to zero offset.
  382.  
  383.         if (-1==iPageEnd)
  384.             iPageEnd=m_cPages-1;
  385.         else
  386.             iPageEnd--;     //Switch to zero offset.
  387.         }
  388.     else //Can't test PD_ALLPAGES with & since it's defined as 0L
  389.         {
  390.         iPageStart=0;
  391.         iPageEnd=m_cPages-1;
  392.         }
  393.  
  394.     //Arrange cycles and repeats depending on cCopies and collating
  395.     if (PD_COLLATE & dwFlags)
  396.         {
  397.         cCycles=cCopies;
  398.         cRepeat=1;
  399.         }
  400.     else
  401.         {
  402.         cCycles=1;
  403.         cRepeat=cCopies;
  404.         }
  405.  
  406.     //Disable the frame window to prevent reentrancy while printing.
  407.     hWndT=GetParent(m_hWnd);
  408.     pDoc=(PCDocument)SendMessage(hWndT, DOCM_PDOCUMENT, 0, 0L);
  409.  
  410.     if (NULL!=pDoc)
  411.         {
  412.         PCFrame pFR;
  413.  
  414.         pFR=pDoc->FrameGet();
  415.         hWndTop=pFR->Window();
  416.         EnableWindow(hWndTop, FALSE);
  417.         }
  418.  
  419.     SetAbortProc(hDC, AbortProc);
  420.     g_fCancelPrint=FALSE;
  421.  
  422.     //If these don't work then we'll just live without a dialog.
  423.     g_hDlgPrint=CreateDialog(m_hInst, MAKEINTRESOURCE(IDD_PRINTING)
  424.         , hWndTop, PrintDlgProc);
  425.  
  426.     //Increment for either direction.
  427.     iPageInc=(iPageStart > iPageEnd) ? -1 : 1;
  428.  
  429.     //Initial entries in dialog box.
  430.     cPages=1+((int)(iPageEnd-iPageStart)*iPageInc);
  431.  
  432.     SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE, 1, (LPARAM)cPages);
  433.     SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, 1, (LPARAM)cRepeat);
  434.  
  435.     di.cbSize=sizeof(DOCINFO);
  436.     di.lpszDocName=pszDoc;
  437.     di.lpszOutput=NULL;
  438.  
  439.     if (StartDoc(hDC, &di) > 0)
  440.         {
  441.         /*
  442.          * Iterate over the pages, repeating each page depending on
  443.          * the copies we want and if we have collate enabled.
  444.          */
  445.  
  446.         for (iCycle=1; iCycle <= cCycles; iCycle++)
  447.             {
  448.             if (PD_COLLATE & dwFlags)
  449.                 {
  450.                 SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE, iCycle
  451.                     , (LPARAM)cCycles);
  452.                 }
  453.  
  454.             //iPageInc controls direction
  455.             for (iPage=iPageStart; ; iPage+=iPageInc)
  456.                 {
  457.                 iUserPage=1+((iPage-(int)iPageStart)*iPageInc);
  458.  
  459.                 SendMessage(g_hDlgPrint, PRINTM_PAGEUPDATE
  460.                     , iUserPage, (LPARAM)cPages);
  461.  
  462.                 m_iPageCur=iPage;   //We restore this later.
  463.  
  464.                 for (iRepeat=1; iRepeat <= cRepeat; iRepeat++)
  465.                     {
  466.                     if (!(PD_COLLATE & dwFlags))
  467.                         {
  468.                         SendMessage(g_hDlgPrint, PRINTM_COPYUPDATE
  469.                             , iRepeat, (LPARAM)cRepeat);
  470.                         }
  471.  
  472.                     StartPage(hDC);
  473.                     Draw(hDC, TRUE, TRUE);
  474.  
  475.                     if (EndPage(hDC) < 0)
  476.                         fError=TRUE;
  477.  
  478.                     if (fError || g_fCancelPrint)
  479.                         break;
  480.                     }
  481.  
  482.                 if (fError || g_fCancelPrint)
  483.                     break;
  484.  
  485.                 //If we just printed the last page, time to quit.
  486.                 if (iPage==(int)iPageEnd)
  487.                     break;
  488.                 }
  489.  
  490.             if (fError || g_fCancelPrint)
  491.                 break;
  492.             }
  493.  
  494.         if (!fError)
  495.             EndDoc(hDC);
  496.         else
  497.             AbortDoc(hDC);
  498.         }
  499.     else
  500.         fError=TRUE;
  501.  
  502.     //Set the page back to what it was before all this started.
  503.     m_iPageCur=iPageHold;
  504.  
  505.     EnableWindow(hWndTop, TRUE);
  506.     SetFocus(hWndTop);
  507.     DestroyWindow(g_hDlgPrint);
  508.     DeleteDC(hDC);
  509.     return !fError;
  510.     }
  511.  
  512.  
  513.  
  514.  
  515.  
  516.  
  517. /*
  518.  * AbortProc
  519.  *
  520.  * Purpose:
  521.  *  Abort procedure for printing the pages.
  522.  *
  523.  * Parameters:
  524.  *  hDC             HDC on which printing is happening.
  525.  *  iErr            int error code.
  526.  *
  527.  * Return Value:
  528.  *  BOOL            TRUE to continue the print job, FALSE otherwise.
  529.  */
  530.  
  531. BOOL APIENTRY AbortProc(HDC hDC, int iErr)
  532.     {
  533.     MSG     msg;
  534.  
  535.     while (!g_fCancelPrint
  536.         && PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  537.         {
  538.         if (NULL==g_hDlgPrint
  539.             || !IsDialogMessage(g_hDlgPrint, &msg))
  540.             {
  541.             TranslateMessage(&msg);
  542.             DispatchMessage(&msg);
  543.             }
  544.         }
  545.  
  546.     return !g_fCancelPrint;
  547.     }
  548.  
  549.  
  550.  
  551.  
  552. /*
  553.  * PrintDlgProc
  554.  *
  555.  * Purpose:
  556.  *  Modeless dialog procedure for the dialog displayed while Patron
  557.  *  is printing pages.
  558.  */
  559.  
  560. BOOL APIENTRY PrintDlgProc(HWND hDlg, UINT iMsg, WPARAM wParam
  561.     , LPARAM lParam)
  562.     {
  563.     TCHAR           szFormat[40];
  564.     TCHAR           szOutput[80];
  565.  
  566.     switch (iMsg)
  567.         {
  568.         case WM_INITDIALOG:
  569.             EnableMenuItem(GetSystemMenu(hDlg, FALSE), SC_CLOSE
  570.                 , MF_GRAYED);
  571.             return TRUE;
  572.  
  573.         case WM_COMMAND:
  574.             //Cancel button was pressed.
  575.             g_fCancelPrint=TRUE;
  576.             ShowWindow(hDlg, SW_HIDE);
  577.             return TRUE;
  578.  
  579.         case PRINTM_PAGEUPDATE:
  580.             GetDlgItemText(hDlg, ID_PAGESTRING, szFormat
  581.                 , sizeof(szFormat));
  582.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  583.             SetDlgItemText(hDlg, ID_CURRENTPAGE, szOutput);
  584.             return TRUE;
  585.  
  586.         case PRINTM_COPYUPDATE:
  587.             GetDlgItemText(hDlg, ID_COPYSTRING, szFormat
  588.                 , sizeof(szFormat));
  589.             wsprintf(szOutput, szFormat, wParam, (UINT)lParam);
  590.             SetDlgItemText(hDlg, ID_CURRENTCOPY, szOutput);
  591.             return TRUE;
  592.         }
  593.  
  594.     return FALSE;
  595.     }
  596.