home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c480 / 17.ddi / SAMPLES / DIBVIEW / PRINT.C_ / PRINT.C
Encoding:
C/C++ Source or Header  |  1993-02-08  |  38.5 KB  |  1,166 lines

  1. /*************************************************************************
  2.  
  3.       File:  PRINT.C
  4.  
  5.    Purpose:  Routines called to print a DIB.  Uses banding or lets GDI
  6.              do the banding.  Works with 3.0 (i.e. via escapes) or 3.1
  7.              (i.e. via printing APIs).
  8.  
  9.  Functions:  DIBPrint
  10.              BandDIBToPrinter
  11.              PrintABand
  12.              DeviceSupportsEscape
  13.              TranslatePrintRect
  14.              GetPrinterDC
  15.              PrintAbortProc
  16.              PrintAbortDlg
  17.              DoStartDoc
  18.              DoSetAbortProc
  19.              DoStartPage
  20.              DoEndPage
  21.              DoEndDoc
  22.              FindGDIFunction
  23.              ShowPrintError
  24.  
  25.   Comments:
  26.  
  27.    History:   Date      Reason
  28.              6/ 1/91    Created
  29.  
  30. *************************************************************************/
  31.  
  32. #include "master.h"
  33.  
  34.  
  35. // The following typedef's are for printing functions.  They are defined
  36. //  in PRINT.H (!!!!!!!!!!!!!!!!!!!!!!!?????) included with the 3.1
  37. //  SDK -- as this app is supposed to compile in 3.0, I define them
  38. //  here instead.
  39.  
  40. typedef struct
  41.    {
  42.    BOOL bGraphics;            // Band includes graphics
  43.    BOOL bText;                // Band includes text.
  44.    RECT GraphicsRect;         // Rectangle to output graphics into.
  45.    }
  46. BANDINFOSTRUCT;
  47.  
  48.  
  49. // LPDOCINFO is now defined in 3.1's WINDOWS.H.  We're compiling under
  50. //  both 3.0 and 3.1.  For now, we'll define our own LPDOCINFO here.
  51. //  This is a LESS than adequate solution!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  52.  
  53. typedef struct
  54.    {
  55.    short cbSize;
  56.    LPSTR lpszDocName;
  57.    LPSTR lpszOutput;
  58.    }
  59. OURDOCINFO, far * LPOURDOCINFO;
  60.  
  61.  
  62.  
  63. // The following typedef's and string variables are used to link to
  64. //  printing functions on-the-fly in Windows 3.1.  These API are not
  65. //  present in Windows 3.0!  As such, we must use GetModuleHandle() and
  66. //  GetProcAddress() to find and call them.
  67.  
  68. typedef int (FAR PASCAL *LPSTARTDOC)     (HDC, LPOURDOCINFO);
  69. typedef int (FAR PASCAL *LPSETABORTPROC) (HDC, FARPROC);
  70. typedef int (FAR PASCAL *LPSTARTPAGE)    (HDC);
  71. typedef int (FAR PASCAL *LPENDPAGE)      (HDC);
  72. typedef int (FAR PASCAL *LPENDDOC)       (HDC);
  73.  
  74.  
  75.    // The following strings are used to link to function within
  76.    //  GDI on-the-fly.  These functions were added in 3.1.  We
  77.    //  can't call them directly, because that would not allow this
  78.    //  application to run under Windows 3.0.  We, therefore, use
  79.    //  GetModuleHandle()/GetProcAddress() to link to these functions.
  80.    //  See FindGDIFunction() below.
  81.  
  82. char szGDIModule[]    = "GDI";         // Module name for GDI in Win31.
  83. char szStartDoc[]     = "StartDoc";    // StartDoc() function in GDI.
  84. char szSetAbortProc[] = "SetAbortProc";// SetAbortProc() function in GDI.
  85. char szStartPage[]    = "StartPage";   // StartPage() function in GDI.
  86. char szEndPage[]      = "EndPage";     // EndPage function in GDI.
  87. char szEndDoc[]       = "EndDoc";      // EndDoc function in GDI.
  88.  
  89.  
  90.  
  91.  
  92. // Globals for this module.
  93.  
  94. static HWND hDlgAbort    = NULL;        // Handle to abort dialog box.
  95. static char szPrintDlg[] = "PrintDLG";  // Name of Print dialog from .RC
  96. static BOOL bAbort       = FALSE;       // Abort a print operation?
  97. static BOOL gbUseEscapes = TRUE;        // Use Escape() or 3.1 printer APIs?
  98.  
  99.  
  100. // Macros
  101.  
  102. #define ChangePrintPercent(nPct)    SendMessage(hDlgAbort, MYWM_CHANGEPCT, nPct, NULL)
  103.  
  104.  
  105.  
  106. // Function prototypes.
  107.  
  108. BOOL FAR PASCAL __export PrintAbortProc (HDC hDC, short code);
  109. int  FAR PASCAL __export PrintAbortDlg  (HWND hWnd,
  110.                             unsigned msg,
  111.                                 WORD wParam,
  112.                                 LONG lParam);
  113.  
  114. DWORD    BandDIBToPrinter    (HDC hPrnDC,
  115.                             LPSTR lpDIBHdr,
  116.                             LPSTR lpBits,
  117.                            LPRECT lpPrintRect);
  118. DWORD    PrintABand          (HDC hDC,
  119.                            LPRECT lpRectOut,
  120.                            LPRECT lpRectClip,
  121.                              BOOL fDoText,
  122.                              BOOL fDoGraphics,
  123.                             LPSTR lpDIBHdr,
  124.                             LPSTR lpDIBBits);
  125. HDC     GetPrinterDC        (void);
  126. void    TranslatePrintRect  (HDC hDC,
  127.                           LPRECT lpPrintRect,
  128.                             WORD wUnits,
  129.                             WORD cxDIB,
  130.                             WORD cyDIB);
  131. DWORD    DoStartDoc          (HDC hPrnDC, LPSTR lpszDocName);
  132. DWORD    DoEndPage           (HDC hPrnDC);
  133. DWORD    DoSetAbortProc      (HDC hPrnDC,
  134.                           FARPROC lpfnAbortProc);
  135. DWORD    DoStartPage         (HDC hPrnDC);
  136. DWORD    DoEndPage           (HDC hPrnDC);
  137. DWORD    DoEndDoc            (HDC hPrnDC);
  138. FARPROC  FindGDIFunction     (LPSTR lpszFnName);
  139. BOOL     DeviceSupportsEscape(HDC hDC,
  140.                              int nEscapeCode);
  141.  
  142.  
  143.  
  144. //---------------------------------------------------------------------
  145. //
  146. // Function:   DIBPrint
  147. //
  148. // Purpose:    This routine drives the printing operation.  It has the code
  149. //             to handle both banding and non-banding printers.  A banding
  150. //             printer can be distinguished by the GetDeviceCaps() API (see
  151. //             the code below.  On banding devices, must repeatedly call the
  152. //             NEXTBAND escape to get the next banding rectangle to print
  153. //             into.  If the device supports the BANDINFO escape, it should
  154. //             be used to determine whether the band "wants" text or
  155. //             graphics (or both).  On non-banding devices, we can ignore
  156. //             all this and call PrintPage() on the entire page!
  157. //
  158. // Parms:      hDIB        == Handle to global memory with a DIB spec in it.
  159. //                              can be either a Win30 DIB or an OS/2 PM DIB.
  160. //             lpPrintRect == Rect to print (decoded based on next parm)
  161. //             wUnits      == Units lpPrintRect is in (see
  162. //                              TranslatePrintRect()).
  163. //             dwROP       == Raster operation to use.
  164. //!!!!!!!!!!!!!!!!!!!!dwROP isn't used !!!!!!!!!!!!!!!!!!!!!!
  165. //             fBanding    == TRUE when want to do banding (use NEXTBAND).
  166. //
  167. // Returns:   Encoded error value -- bitwise combination of ERR_PRN_*
  168. //             in PRINT.H.  More than one error can be returned --
  169. //             the application can parse the bits in the DWORD returned,
  170. //             or call ShowPrintError() to display all the errors
  171. //             that ocurred.
  172. //
  173. // History:   Date      Reason
  174. //             6/01/91  Created
  175. //            10/26/91  Added error return codes.
  176. //                      Use DeviceSupportsEscape() instead
  177. //                        of QUERYESCSUPPORT.
  178. //            10/29/91  Added the fUse31APIs flag.
  179. //            11/14/91  Added more error checking.
  180. //                      Added lpDocName as a parameter.
  181. //
  182. //---------------------------------------------------------------------
  183.  
  184. DWORD DIBPrint (HANDLE hDIB,
  185.                 LPRECT lpPrintRect,
  186.                   WORD wUnits,
  187.                  DWORD dwROP,
  188.                   BOOL fBanding,
  189.                   BOOL fUse31APIs,
  190.                  LPSTR lpszDocName)
  191. {
  192.    HDC            hPrnDC;
  193.    RECT           rect;
  194.    static FARPROC lpAbortProc;
  195.    static FARPROC lpAbortDlg;
  196.    LPSTR          lpDIBHdr, lpBits;
  197.    DWORD          dwErr = ERR_PRN_NONE;
  198.  
  199.  
  200.       // Do some setup (like getting pointers to the DIB and its header,
  201.       //  and a printer DC).  Also, set the global gbUseEscapes to force
  202.       //  using printer escapes or the 3.1 printing API.
  203.  
  204.    if (!hDIB)
  205.       return ERR_PRN_NODIB;
  206.  
  207.    gbUseEscapes = !fUse31APIs;
  208.    lpDIBHdr     = GlobalLock (hDIB);
  209.    lpBits       = FindDIBBits (lpDIBHdr);
  210.  
  211.    if (hPrnDC = GetPrinterDC ())
  212.       {
  213.       SetStretchBltMode (hPrnDC, COLORONCOLOR);
  214.       TranslatePrintRect (hPrnDC,
  215.                           lpPrintRect,
  216.                           wUnits,
  217.                           (WORD) DIBWidth (lpDIBHdr),
  218.                           (WORD) DIBHeight (lpDIBHdr));
  219.  
  220.  
  221.          // Initialize the abort procedure.  Then STARTDOC.
  222.  
  223.       lpAbortProc = MakeProcInstance(PrintAbortProc, hInst);
  224.       lpAbortDlg  = MakeProcInstance(PrintAbortDlg,  hInst);
  225.       hDlgAbort   = CreateDialog(hInst, szPrintDlg, GetFocus (), lpAbortDlg);
  226.       bAbort      = FALSE;
  227.  
  228.       if (dwErr |= DoSetAbortProc (hPrnDC, lpAbortProc))
  229.          goto PRINTERRORCLEANUP;
  230.  
  231.       if (dwErr |= DoStartDoc (hPrnDC, lpszDocName))
  232.          goto PRINTERRORCLEANUP;
  233.  
  234.       if (fBanding)
  235.          dwErr |= BandDIBToPrinter (hPrnDC, lpDIBHdr, lpBits, lpPrintRect);
  236.       else
  237.          {
  238.             // When not doing banding, call PrintABand() to dump the
  239.             //  entire page to the printer in one shot (i.e. give it
  240.             //  a band that covers the entire printing rectangle,
  241.             //  and tell it to print graphics and text).
  242.  
  243.          rect = *lpPrintRect;
  244.  
  245.          dwErr |= PrintABand (hPrnDC,
  246.                               lpPrintRect,
  247.                               &rect,
  248.                               TRUE,
  249.                               TRUE,
  250.                               lpDIBHdr,
  251.                               lpBits);
  252.  
  253.  
  254.             // Non-banding devices need the NEWFRAME or EndPage() call.
  255.  
  256.          dwErr |= DoEndPage (hPrnDC);
  257.          }
  258.  
  259.  
  260.  
  261.          // End the print operation.  Only send the ENDDOC if
  262.          //   we didn't abort or error.
  263.  
  264.       if (!bAbort)
  265.          dwErr |= DoEndDoc (hPrnDC);
  266.  
  267.  
  268.          // All done, clean up.
  269.  
  270. PRINTERRORCLEANUP:
  271.       DestroyWindow (hDlgAbort);
  272.  
  273.       FreeProcInstance(lpAbortProc);
  274.       FreeProcInstance(lpAbortDlg);
  275.  
  276.       DeleteDC (hPrnDC);
  277.       }
  278.    else
  279.       dwErr |= ERR_PRN_NODC;
  280.  
  281.    GlobalUnlock (hDIB);
  282.  
  283.    return dwErr;
  284. }
  285.  
  286.  
  287.  
  288. //---------------------------------------------------------------------
  289. //
  290. // Function:   BandDIBToPrinter
  291. //
  292. // Purpose:    Repeatedly call the NEXTBAND escape to get the next
  293. //             banding rectangle to print into.  If the device supports
  294. //             the BANDINFO escape, use it to determine whether the band
  295. //             wants text or graphics (or both).  For each band, call
  296. //             PrintABand() to do the actual output.
  297. //
  298. // Parms:      hPrnDC   == DC to printer.
  299. //             lpDIBHdr == Ptr to DIB header (BITMAPINFOHEADER or
  300. //                         BITMAPCOREHEADER)
  301. //             lpBits   == Ptr to DIB's bitmap bits.
  302. //
  303. // Returns:    WORD -- One (or more) of the printer errors defined as
  304. //             ERR_PRN_* in PRINT.H.
  305. //
  306. //             ERR_PRN_NONE (0) if no error.
  307. //
  308. // History:   Date      Reason
  309. //            10/26/91  Chopped out of DIBPrint().
  310. //                      Use DeviceSupportsEscape() instead of
  311. //                        QUERYESCSUPPORT.
  312. //            11/14/91  Added Error return codes ERR_PRN_BANDINFO
  313. //                        and errors from PrintABand.
  314. //            01/22/91  Fixed NEXTBAND error return check (was checking
  315. //                        if != 0, now check if > 0).
  316. //
  317. //---------------------------------------------------------------------
  318.  
  319. DWORD BandDIBToPrinter (HDC hPrnDC,
  320.                       LPSTR lpDIBHdr,
  321.                       LPSTR lpBits,
  322.                      LPRECT lpPrintRect)
  323. {
  324.    BANDINFOSTRUCT bi;
  325.    BOOL           bBandInfoDevice;
  326.    RECT           rect;
  327.    DWORD          dwError = ERR_PRN_NONE;
  328.    int            nEscRet;
  329.  
  330.  
  331.       // All printers should support the NEXTBAND escape -- we'll
  332.       //  check here, just in case, though!
  333.  
  334.    if (!DeviceSupportsEscape (hPrnDC, NEXTBAND))
  335.       return ERR_PRN_CANTBAND;
  336.  
  337.  
  338.       // Check if device supports the BANDINFO escape.  Then setup
  339.       //  the BANDINFOSTRUCT (we'll use the values we put into it
  340.       //  here later even if the device doesn't support BANDINFO).
  341.  
  342.    bBandInfoDevice = DeviceSupportsEscape (hPrnDC, BANDINFO);
  343.    bi.bGraphics    = TRUE;
  344.    bi.bText        = TRUE;
  345.    bi.GraphicsRect = *lpPrintRect;
  346.  
  347.  
  348.       // Enter the banding loop.  For each band, call BANDINFO if
  349.       //  appropriate.  Then call PrintABand() to do the actual
  350.       //  output.  Terminate loop when NEXTBAND returns an empty rect.
  351.  
  352.    while (((nEscRet = Escape (hPrnDC, NEXTBAND, NULL, NULL, (LPSTR) &rect)) > 0) &&
  353.          !IsRectEmpty (&rect))
  354.       {
  355.       if (bBandInfoDevice)
  356.          if (!Escape (hPrnDC,
  357.                       BANDINFO,
  358.                       sizeof (BANDINFOSTRUCT),
  359.                       (LPSTR) &bi,
  360.                       (LPSTR) &bi))
  361.             dwError |= ERR_PRN_BANDINFO;
  362.  
  363.       dwError |= PrintABand (hPrnDC,
  364.                              lpPrintRect,
  365.                              &rect,
  366.                              bi.bText,
  367.                              bi.bGraphics,
  368.                              lpDIBHdr,
  369.                              lpBits);
  370.       }
  371.  
  372.    if (nEscRet <= 0)
  373.       dwError |= ERR_PRN_NEXTBAND;
  374.  
  375.    return dwError;
  376. }
  377.  
  378.  
  379.  
  380.  
  381. //---------------------------------------------------------------------
  382. //
  383. // Function:   PrintABand
  384. //
  385. // Purpose:    This routine does ALL output to the printer.  It is driven by
  386. //             BandDIBToPrinter().  It is called for both banding and non-
  387. //             banding printing devices.  lpClipRect contains the rectangular
  388. //             area we should do our output into (i.e. we should clip our
  389. //             output to this area).  The flags fDoText and fDoGraphics
  390. //             should be set appropriately (if we want any text output to
  391. //             the rectangle, set fDoText to true).  Normally these flags
  392. //             are returned on banding devices which support the BANDINFO
  393. //             escape.  On non-banding devices, all output goes to the
  394. //             entire page, so this routine is passes a rectangle for
  395. //             the entire page, and fDoText = fDoGraphics = TRUE.
  396. //
  397. //             This routine is also responsible for doing stretching of
  398. //             the DIB.  As such, the lpRectOut parameter points to a
  399. //             rectangle on the printed page where the entire DIB will
  400. //             fit -- the DIB is stretched appropriately to fit in this
  401. //             rectangle.
  402. //
  403. //             After printing a band, updates the print % shown in the
  404. //             abort dialog box.
  405. //
  406. // Parms:      hDC         == DC to do output into.
  407. //             lpRectOut   == Rectangle on DC DIB should fit in.
  408. //             lpRectClip  == Rectangle to output during THIS call.
  409. //             fDoText     == Output text into this rectangle (unused by DIBView)?
  410. //             fDoGraphics == Output graphics into this rectangle?
  411. //             lpDIBHdr    == Pointer to DIB's header (either a
  412. //                              BITMAPINFOHEADER or a BITMAPCOREHEADER)
  413. //             lpDIBBits   == Pointer to the DIB's bitmap bits.
  414. //
  415. // Returns:    One or more of the ERR_PRN_* errors in PRINT.H (or'd
  416. //             together. ERR_PRN_NONE (0) if no error.
  417. //
  418. // History:   Date      Reason
  419. //             6/01/91  Created
  420. //
  421. //---------------------------------------------------------------------
  422.  
  423. DWORD PrintABand (HDC hDC,
  424.                LPRECT lpRectOut,
  425.                LPRECT lpRectClip,
  426.                  BOOL fDoText,
  427.                  BOOL fDoGraphics,
  428.                 LPSTR lpDIBHdr,
  429.                 LPSTR lpDIBBits)
  430. {
  431.    int    nxLogPix, nyLogPix;
  432.    RECT   rect;
  433.    double dblXScaling, dblYScaling;
  434.    DWORD  dwError = ERR_PRN_NONE;
  435.  
  436.  
  437.    if (fDoGraphics)
  438.       {
  439.       nxLogPix = GetDeviceCaps (hDC, LOGPIXELSX);
  440.       nyLogPix = GetDeviceCaps (hDC, LOGPIXELSY);
  441.  
  442.       dblXScaling = ((double) lpRectOut->right - lpRectOut->left) /
  443.                      DIBWidth (lpDIBHdr);
  444.       dblYScaling = ((double) lpRectOut->bottom - lpRectOut->top) /
  445.                      DIBHeight (lpDIBHdr);
  446.  
  447.  
  448.          // Now we set up a temporary rectangle -- this rectangle
  449.          //  holds the coordinates on the paper where our bitmap
  450.          //  WILL be output.  We can intersect this rectangle with
  451.          //  the lpClipRect to see what we NEED to output to this
  452.          //  band.  Then, we determine the coordinates in the DIB
  453.          //  to which this rectangle corresponds (using dbl?Scaling).
  454.  
  455.       IntersectRect (&rect, lpRectOut, lpRectClip);
  456.  
  457.       if (!IsRectEmpty (&rect))
  458.          {
  459.          RECT rectIn;
  460.          int  nPct;
  461.  
  462.          rectIn.left   = (int) ((rect.left - lpRectOut->left) /
  463.                                  dblXScaling + 0.5);
  464.          rectIn.top    = (int) ((rect.top  - lpRectOut->top) /
  465.                                  dblYScaling + 0.5);
  466.          rectIn.right  = (int) (rectIn.left + (rect.right  - rect.left) /
  467.                                  dblXScaling + 0.5);
  468.          rectIn.bottom = (int) (rectIn.top  +  (rect.bottom - rect.top) /
  469.                                  dblYScaling + 0.5);
  470.  
  471.             // Could just always call StretchDIBits() below, but
  472.             //  we want to give SetDIBitsToDevice() a work out, too!
  473.  
  474.          if ((rect.right - rect.left == rectIn.right - rectIn.left) &&
  475.              (rect.bottom - rect.top == rectIn.bottom - rectIn.top))
  476.             {
  477.             if (!SetDIBitsToDevice (hDC,                            // DestDC
  478.                                     rect.left,                      // DestX
  479.                                     rect.top,                  // DestY
  480.                                     rect.right - rect.left,    // DestWidth
  481.                                     rect.bottom - rect.top,    // DestHeight
  482.                                     rectIn.left,               // SrcX
  483.                                     (int) DIBHeight (lpDIBHdr)-// SrcY
  484.                                        rectIn.top -
  485.                                        (rectIn.bottom - rectIn.top),
  486.                                     0,                         // nStartScan
  487.                                     (int) DIBHeight (lpDIBHdr),// nNumScans
  488.                                     lpDIBBits,                 // lpBits
  489.                                     (LPBITMAPINFO) lpDIBHdr,   // lpBitInfo
  490.                                     DIB_RGB_COLORS))           // wUsage
  491.                dwError |= ERR_PRN_SETDIBITSTODEV;
  492.             }
  493.          else
  494.             {
  495.             if (!StretchDIBits (hDC,                           // DestDC
  496.                                 rect.left,                     // DestX
  497.                                 rect.top,                      // DestY
  498.                                 rect.right - rect.left,        // DestWidth
  499.                                 rect.bottom - rect.top,        // DestHeight
  500.                                 rectIn.left,                   // SrcX
  501.                                 (int) DIBHeight (lpDIBHdr) -   // SrcY
  502.                                    rectIn.top -
  503.                                    (rectIn.bottom - rectIn.top),
  504.                                 rectIn.right - rectIn.left,    // SrcWidth
  505.                                 rectIn.bottom - rectIn.top,    // SrcHeight
  506.                                 lpDIBBits,                     // lpBits
  507.                                 (LPBITMAPINFO) lpDIBHdr,       // lpBitInfo
  508.                                 DIB_RGB_COLORS,                // wUsage
  509.                                 SRCCOPY))                      // dwROP
  510.                dwError |= ERR_PRN_STRETCHDIBITS;
  511.             }
  512.  
  513.  
  514.             // Change percentage of print shown in abort dialog.
  515.  
  516.          nPct = MulDiv (rect.bottom,
  517.                         100,
  518.                         lpRectOut->bottom);
  519.          ChangePrintPercent (nPct);
  520.          }
  521.       }
  522.  
  523.    return dwError;
  524. }
  525.  
  526.  
  527.  
  528. //---------------------------------------------------------------------
  529. //
  530. // Function:   DeviceSupportsEscape
  531. //
  532. // Purpose:    Uses QUERYESCSUPPORT to see if the given device
  533. //             supports the given escape code.
  534. //
  535. // Parms:      hDC         == Device to check if escape is supported on.
  536. //             nEscapeCode == Escape code to check for.
  537. //
  538. // History:   Date      Reason
  539. //            10/26/91  Created
  540. //
  541. //---------------------------------------------------------------------
  542.  
  543. BOOL DeviceSupportsEscape (HDC hDC, int nEscapeCode)
  544. {
  545.    return Escape(hDC, QUERYESCSUPPORT, sizeof(int), (LPSTR) &nEscapeCode, NULL);
  546. }
  547.  
  548.  
  549.  
  550. //---------------------------------------------------------------------
  551. //
  552. // Function:   TranslatePrintRect
  553. //
  554. // Purpose:    Given a rectangle and what units that rectangle is in,
  555. //             translate the rectangle to the appropriate value in
  556. //             device units.
  557. //
  558. // Parms:      hDC         == DC translation is relative to.
  559. //             lpPrintRect == Pointer to rectangle to translate.
  560. //             wUnits      == Units lpPrintRect is in:
  561. //                              UNITS_INCHES == Units are in inches, stretch
  562. //                                                DIB to this size on page.
  563. //                              UNITS_STRETCHTOPAGE == lpPrintRect doesn't
  564. //                                                matter, stretch DIB to
  565. //                                                fill the entire page.
  566. //                              UNITS_BESTFIT == lpPrintRect doesn't matter,
  567. //                                                stretch DIB as much as
  568. //                                                possible horizontally,
  569. //                                                and preserve its aspect
  570. //                                                ratio vertically.
  571. //                              UNITS_SCALE == lpPrintRect->top is factor to
  572. //                                                stretch vertically.
  573. //                                                lpPrintRect->left is
  574. //                                                factor to stretch horiz.
  575. //                              UNITS_PIXELS == lpPrintRect is in pixels.
  576. //             cxDIB       == DIB's width.
  577. //             cyDIB       == DIB's height.
  578. //
  579. // History:   Date      Reason
  580. //             6/01/91  Created
  581. //
  582. //---------------------------------------------------------------------
  583.  
  584. void TranslatePrintRect (HDC hDC,
  585.                       LPRECT lpPrintRect,
  586.                         WORD wUnits,
  587.                         WORD cxDIB,
  588.                         WORD cyDIB)
  589. {
  590.    int cxPage, cyPage, cxInch, cyInch;
  591.  
  592.    if (!hDC)
  593.       return;
  594.  
  595.    cxPage = GetDeviceCaps (hDC, HORZRES);
  596.    cyPage = GetDeviceCaps (hDC, VERTRES);
  597.    cxInch = GetDeviceCaps (hDC, LOGPIXELSX);
  598.    cyInch = GetDeviceCaps (hDC, LOGPIXELSY);
  599.  
  600.    switch (wUnits)
  601.       {
  602.          // lpPrintRect contains units in inches.  Convert to pixels.
  603.  
  604.       case UNITS_INCHES:
  605.          lpPrintRect->top    *= cyInch;
  606.          lpPrintRect->left   *= cxInch;
  607.          lpPrintRect->bottom *= cyInch;
  608.          lpPrintRect->right  *= cxInch;
  609.          break;
  610.  
  611.  
  612.          // lpPrintRect contains no pertinent info -- create a rectangle
  613.          //  which covers the entire printing page.
  614.  
  615.       case UNITS_STRETCHTOPAGE:
  616.          lpPrintRect->top    = 0;
  617.          lpPrintRect->left   = 0;
  618.          lpPrintRect->bottom = cyPage;
  619.          lpPrintRect->right  = cxPage;
  620.          break;
  621.  
  622.  
  623.          // lpPrintRect contains no pertinent info -- create a rectangle
  624.          //  which preserves the DIB's aspect ratio, and fills the page
  625.          //  horizontally.  NOTE:  Assumes DIB is 1 to 1 aspect ratio,
  626.          //  could use biXPelsPerMeter in a DIB to munge these values
  627.          //  for non 1 to 1 aspect ratio DIBs (I've never seen such
  628.          //  a beast, though)!
  629.  
  630.       case UNITS_BESTFIT:
  631.          lpPrintRect->top    = 0;
  632.          lpPrintRect->left   = 0;
  633.          lpPrintRect->bottom = (int)(((double) cyDIB * cyPage * cyInch) /
  634.                                      ((double) cxDIB * cxInch));
  635.          lpPrintRect->right  = cxPage;
  636.          break;
  637.  
  638.  
  639.  
  640.          // lpPrintRect's top/left contain multipliers to multiply the
  641.          //  DIB's height/width by.
  642.  
  643.       case UNITS_SCALE:
  644.          {
  645.          int cxMult, cyMult;
  646.  
  647.          cxMult              = lpPrintRect->left;
  648.          cyMult              = lpPrintRect->top;
  649.          lpPrintRect->top    = 0;
  650.          lpPrintRect->left   = 0;
  651.          lpPrintRect->bottom = cyDIB * cyMult;
  652.          lpPrintRect->right  = cxDIB * cxMult;
  653.          }
  654.  
  655.  
  656.          // lpPrintRect already contains device units, don't touch it.
  657.  
  658.       case UNITS_PIXELS:
  659.       default:
  660.          // Don't touch the units...
  661.          break;
  662.       }
  663. }
  664.  
  665.  
  666.  
  667.  
  668.  
  669. //---------------------------------------------------------------------
  670. //
  671. // Function:   GetPrinterDC
  672. //
  673. // Purpose:    Returns a DC to the currently selected printer.  Returns
  674. //             NULL on error.
  675. //
  676. // Parms:      None
  677. //
  678. // History:   Date      Reason
  679. //             6/01/91  Created
  680. //
  681. //---------------------------------------------------------------------
  682.  
  683. HDC GetPrinterDC (void)
  684. {
  685.    PRINTDLG pd;
  686.  
  687.    pd.lStructSize          = sizeof (pd);
  688.    pd.hwndOwner            = NULL;
  689.    pd.hDevMode             = NULL;
  690.    pd.hDevNames            = NULL;
  691.    pd.hDC                  = NULL;
  692.    pd.Flags                = PD_RETURNDC | PD_RETURNDEFAULT;
  693.    pd.nFromPage            = 0;
  694.    pd.nToPage              = 0;
  695.    pd.nMinPage             = 0;
  696.    pd.nMaxPage             = 0;
  697.    pd.nCopies              = 0;
  698.    pd.hInstance            = NULL;
  699.    pd.lCustData            = NULL;
  700.    pd.lpfnPrintHook        = NULL;
  701.    pd.lpfnSetupHook        = NULL;
  702.    pd.lpPrintTemplateName  = NULL;
  703.    pd.lpSetupTemplateName  = NULL;
  704.    pd.hPrintTemplate       = NULL;
  705.    pd.hSetupTemplate       = NULL;
  706.  
  707.    if (PrintDlg (&pd))
  708.       return pd.hDC;
  709.    else
  710.       return NULL;
  711. }
  712.  
  713.  
  714.  
  715.  
  716.  
  717.  
  718. //-------------------- Abort Routines ----------------------------
  719.  
  720.  
  721. //---------------------------------------------------------------------
  722. //
  723. // Function:   PrintAbortProc
  724. //
  725. // Purpose:    Abort procedure while printing is occurring.  Registered
  726. //             with Windows via the SETABORTPROC escape.  This routine
  727. //             is called regularly by the sytem during a print operation.
  728. //
  729. //             By putting a PeekMessage loop here, multitasking can occur.
  730. //             PeekMessage will yield to other apps if they have messages
  731. //             waiting for them.
  732. //
  733. //             Doesn't bother if the global, bAbort, is set.  This var
  734. //             is set by PrintAbortDlg() when a user cancels a print
  735. //             operation.
  736. //
  737. // Parms:      hDC  == DC printing is being done to
  738. //             code == Error code (see docs for SETABORTPROC printer
  739. //                      escape).
  740. //
  741. // History:   Date      Reason
  742. //             6/01/91  Created
  743. //
  744. //---------------------------------------------------------------------
  745.  
  746. BOOL FAR PASCAL __export PrintAbortProc(HDC hDC, short code)
  747. {
  748.    MSG msg;
  749.  
  750.    bAbort |= (code != 0);
  751.  
  752.    while (!bAbort && PeekMessage (&msg, 0, 0, 0, PM_REMOVE))
  753.       if (!IsDialogMessage (hDlgAbort, &msg))
  754.          {
  755.          TranslateMessage (&msg);
  756.          DispatchMessage (&msg);
  757.          }
  758.  
  759.    return (!bAbort);
  760. }
  761.  
  762.  
  763.  
  764. //---------------------------------------------------------------------
  765. //
  766. // Function:   PrintAbortDlg
  767. //
  768. // Purpose:    Dialog box window procedure for the "cancel" dialog
  769. //             box put up while DIBView is printing.
  770. //
  771. //             Functions sets bAbort (a global variable) to true
  772. //             if the user aborts the print operation.  Other functions
  773. //             in this module then "do the right thing."
  774. //
  775. //             Also handles MYWM_CHANGEPCT to change % done displayed
  776. //             in dialog box.
  777. //
  778. // Parms:      hWnd    == Handle to this dialog box.
  779. //             message == Message for window.
  780. //             wParam  == Depends on message.
  781. //             lParam  == Depends on message.
  782. //
  783. // History:   Date      Reason
  784. //             6/01/91  Created
  785. //
  786. //---------------------------------------------------------------------
  787.  
  788. int FAR PASCAL __export PrintAbortDlg(HWND hWnd, unsigned msg, WORD wParam, LONG lParam)
  789. {
  790.    switch (msg)
  791.       {
  792.       case WM_INITDIALOG:
  793.          SetFocus(hWnd);
  794.          return TRUE;
  795.  
  796.  
  797.       case WM_COMMAND:
  798.          bAbort = TRUE;
  799.          return TRUE;
  800.  
  801.  
  802.       case MYWM_CHANGEPCT:
  803.          {
  804.          char szBuf[20];
  805.  
  806.          wsprintf (szBuf, "%3d%% done", wParam);
  807.          SetDlgItemText (hWnd, IDD_PRNPCT, szBuf);
  808.          return TRUE;
  809.          }
  810.       }
  811.  
  812.    return FALSE;
  813. }
  814.  
  815.  
  816.  
  817. //---------------------------------------------------------------------
  818. //
  819. // Function:   DoStartDoc
  820. //
  821. // Purpose:    Called at the beginning of printing a document.  Does
  822. //             the "right thing," depending on whether we're using
  823. //             3.0 style printer escapes, or the 3.1 printing API
  824. //             (i.e. either does an Escape(STARTDOC) or StartDoc()).
  825. //
  826. //             Note that it uses FindGDIFunction() to find the address
  827. //             of StartDoc() we can't just put a call to StartDoc()
  828. //             here because we want this .EXE file to be compatible with
  829. //             Windows 3.0 as well as 3.1.  3.0 didn't have a function
  830. //             "StartDoc()!"
  831. //
  832. // Parms:      hPrnDC == DC to printer
  833. //
  834. // Returns:    An error code defined as ERR_PRN_* in PRINT.H:
  835. //                ERR_PRN_NONE (0) if no error.
  836. //
  837. // History:   Date      Reason
  838. //             6/01/91  Created
  839. //            11/14/91  Added error return code.
  840. //
  841. //---------------------------------------------------------------------
  842.  
  843. DWORD DoStartDoc (HDC hPrnDC, LPSTR lpszDocName)
  844. {
  845.    if (gbUseEscapes)
  846.       {
  847.       if (Escape (hPrnDC, STARTDOC, lstrlen (lpszDocName),
  848.                   lpszDocName, NULL) < 0)
  849.          return ERR_PRN_STARTDOC;
  850.       }
  851.    else
  852.       {
  853.       LPSTARTDOC Win31StartDoc;
  854.       OURDOCINFO DocInfo;
  855.  
  856.       Win31StartDoc       = (LPSTARTDOC) FindGDIFunction (szStartDoc);
  857.       DocInfo.cbSize      = sizeof (DocInfo);
  858.       DocInfo.lpszDocName = lpszDocName;
  859.       DocInfo.lpszOutput  = NULL;
  860.  
  861.       if (Win31StartDoc)
  862.          {
  863.          if (Win31StartDoc (hPrnDC, &DocInfo) < 0)
  864.             return ERR_PRN_STARTDOC;
  865.          }
  866.       else
  867.          return ERR_PRN_NOFNSTARTDOC;
  868.       }
  869.  
  870.    return ERR_PRN_NONE;
  871. }
  872.  
  873.  
  874.  
  875.  
  876. //---------------------------------------------------------------------
  877. //
  878. // Function:   DoSetAbortProc
  879. //
  880. // Purpose:    Called at the beginning of printing a document.  Does
  881. //             the "right thing," depending on whether we're using
  882. //             3.0 style printer escapes, or the 3.1 printing API
  883. //             (i.e. either does an Escape(SETABORTPROC) or SetAbortProc()).
  884. //
  885. //             Note that it uses FindGDIFunction() to find the address
  886. //             of SetAbortProc() we can't just put a call to SetAbortProc()
  887. //             here because we want this .EXE file to be compatible with
  888. //             Windows 3.0 as well as 3.1.  3.0 didn't have a function
  889. //             "SetAbortProc()!"
  890. //
  891. // Parms:      hPrnDC == DC to printer
  892. //
  893. // Returns:    An error code defined as ERR_PRN_* in PRINT.H:
  894. //                ERR_PRN_NONE (0) if no error.
  895. //
  896. // History:   Date      Reason
  897. //             6/01/91  Created
  898. //            11/14/91  Added error return code.
  899. //
  900. //---------------------------------------------------------------------
  901.  
  902. DWORD DoSetAbortProc (HDC hPrnDC, FARPROC lpfnAbortProc)
  903. {
  904.    LPSETABORTPROC Win31SetAbortProc;
  905.  
  906.    if (gbUseEscapes)
  907.       {
  908.       if (Escape(hPrnDC, SETABORTPROC, NULL, (LPSTR) lpfnAbortProc, NULL) < 0)
  909.          return ERR_PRN_SETABORTPROC;
  910.       }
  911.    else
  912.       {
  913.       Win31SetAbortProc = (LPSETABORTPROC) FindGDIFunction (szSetAbortProc);
  914.       if (Win31SetAbortProc)
  915.          {
  916.          if (Win31SetAbortProc (hPrnDC, lpfnAbortProc) < 0)
  917.            return ERR_PRN_SETABORTPROC;
  918.          }
  919.       else
  920.          return ERR_PRN_NOFNSETABORTPROC;
  921.       }
  922.  
  923.    return ERR_PRN_NONE;
  924. }
  925.  
  926.  
  927.  
  928. //---------------------------------------------------------------------
  929. //
  930. // Function:   DoStartPage
  931. //
  932. // Purpose:    Called at the beginning of printing a page.  Does
  933. //             the "right thing," depending on whether we're using
  934. //             3.0 style printer escapes, or the 3.1 printing API.
  935. //             Routine does nothing under 3.0 or when using the 3.0
  936. //             Escapes, as there was no equivalent to StartPage()
  937. //             in 3.0.
  938. //
  939. //             Note that it uses FindGDIFunction() to find the address
  940. //             of StartPage() we can't just put a call to StartPage()
  941. //             here because we want this .EXE file to be compatible with
  942. //             Windows 3.0 as well as 3.1.  3.0 didn't have a function
  943. //             "StartPage()!"
  944. //
  945. // Parms:      hPrnDC == DC to printer
  946. //
  947. // Returns:    An error code defined as ERR_PRN_* in PRINT.H:
  948. //                ERR_PRN_NONE (0) if no error.
  949. //
  950. // History:   Date      Reason
  951. //             6/01/91  Created
  952. //            11/14/91  Added error return code.
  953. //
  954. //---------------------------------------------------------------------
  955.  
  956. DWORD DoStartPage (HDC hPrnDC)
  957. {
  958.    LPSTARTPAGE Win31StartPage;
  959.  
  960.    if (!gbUseEscapes)
  961.       {
  962.       Win31StartPage = (LPSTARTPAGE) FindGDIFunction (szStartPage);
  963.       if (Win31StartPage)
  964.          {
  965.          if (!Win31StartPage (hPrnDC))
  966.             return ERR_PRN_STARTPAGE;
  967.          }
  968.       else
  969.          return ERR_PRN_NOFNSTARTPAGE;
  970.       }
  971.  
  972.    return ERR_PRN_NONE;
  973. }
  974.  
  975.  
  976.  
  977. //---------------------------------------------------------------------
  978. //
  979. // Function:   DoEndPage
  980. //
  981. // Purpose:    Called at the end of printing a page.  Does the
  982. //             "right thing," depending on whether we're using
  983. //             3.0 style printer escapes, or the 3.1 printing API
  984. //             (i.e. either does an Escape(NEWFRAME) or EndPage()).
  985. //
  986. //             Note that it uses FindGDIFunction() to find the address
  987. //             of EndPage() we can't just put a call to EndPage()
  988. //             here because we want this .EXE file to be compatible with
  989. //             Windows 3.0 as well as 3.1.  3.0 didn't have a function
  990. //             "EndPage()!"
  991. //
  992. // Parms:      hPrnDC == DC to printer
  993. //
  994. // Returns:    An error code defined as ERR_PRN_* in PRINT.H:
  995. //                ERR_PRN_NONE (0) if no error.
  996. //
  997. // History:   Date      Reason
  998. //             6/01/91  Created
  999. //            11/14/91  Added error return code.
  1000. //
  1001. //---------------------------------------------------------------------
  1002.  
  1003. DWORD DoEndPage (HDC hPrnDC)
  1004. {
  1005.    LPENDPAGE Win31EndPage;
  1006.  
  1007.    if (gbUseEscapes)
  1008.       {
  1009.       if (Escape (hPrnDC, NEWFRAME, NULL, NULL, NULL) < 0)
  1010.          return ERR_PRN_NEWFRAME;
  1011.       }
  1012.    else
  1013.       {
  1014.       Win31EndPage = (LPENDPAGE) FindGDIFunction (szEndPage);
  1015.       if (Win31EndPage)
  1016.          {
  1017.          if (Win31EndPage (hPrnDC) < 0)
  1018.             return ERR_PRN_NEWFRAME;
  1019.          }
  1020.       else
  1021.          return ERR_PRN_NOFNENDPAGE;
  1022.       }
  1023.  
  1024.    return ERR_PRN_NONE;
  1025. }
  1026.  
  1027.  
  1028.  
  1029. //---------------------------------------------------------------------
  1030. //
  1031. // Function:   DoEndDoc
  1032. //
  1033. // Purpose:    Called at the end of printing a document.  Does
  1034. //             the "right thing," depending on whether we're using
  1035. //             3.0 style printer escapes, or the 3.1 printing API
  1036. //             (i.e. either does an Escape(ENDDOC) or EndDoc()).
  1037. //
  1038. //             Note that it uses FindGDIFunction() to find the address
  1039. //             of EndDoc() we can't just put a call to EndDoc()
  1040. //             here because we want this .EXE file to be compatible with
  1041. //             Windows 3.0 as well as 3.1.  3.0 didn't have a function
  1042. //             "EndDoc()!"
  1043. //
  1044. // Parms:      hPrnDC == DC to printer
  1045. //
  1046. // Returns:    An error code defined as ERR_PRN_* in PRINT.H:
  1047. //                ERR_PRN_NONE (0) if no error.
  1048. //
  1049. // History:   Date      Reason
  1050. //             6/01/91  Created
  1051. //            11/14/91  Added error return code.
  1052. //
  1053. //---------------------------------------------------------------------
  1054.  
  1055. DWORD DoEndDoc (HDC hPrnDC)
  1056. {
  1057.    LPENDDOC Win31EndDoc;
  1058.  
  1059.    if (gbUseEscapes)
  1060.       {
  1061.       if (Escape(hPrnDC, ENDDOC, NULL, NULL, NULL) < 0)
  1062.          return ERR_PRN_ENDDOC;
  1063.       }
  1064.    else
  1065.       {
  1066.       Win31EndDoc = (LPENDDOC) FindGDIFunction (szEndDoc);
  1067.       if (Win31EndDoc)
  1068.          {
  1069.          if (Win31EndDoc (hPrnDC) < 0)
  1070.             return ERR_PRN_ENDDOC;
  1071.          }
  1072.       else
  1073.          return ERR_PRN_NOFNENDDOC;
  1074.       }
  1075.  
  1076.    return ERR_PRN_NONE;
  1077. }
  1078.  
  1079.  
  1080.  
  1081.  
  1082. //---------------------------------------------------------------------
  1083. //
  1084. // Function:   FindGDIFunction
  1085. //
  1086. // Purpose:    Uses GetModuleHandle() and GetProcAddress() to find
  1087. //             a given function inside GDI itself.  This is useful
  1088. //             to "link" to functions on-the-fly that are only
  1089. //             present in Windows 3.1.  If we were to call these
  1090. //             functions directly from this EXE file, Windows 3.0 would
  1091. //             complain that we are not calling valid functions.
  1092. //
  1093. // Parms:      lpszFnName == Name of function within GDI.EXE to find
  1094. //                            an address for.
  1095. //
  1096. // History:   Date      Reason
  1097. //             6/01/91  Created
  1098. //
  1099. //---------------------------------------------------------------------
  1100.  
  1101. FARPROC FindGDIFunction (LPSTR lpszFnName)
  1102. {
  1103.    HANDLE hGDI;
  1104.  
  1105.    hGDI = GetModuleHandle (szGDIModule);
  1106.  
  1107.    if (!hGDI)
  1108.       return NULL;
  1109.  
  1110.    return GetProcAddress (hGDI, lpszFnName);
  1111. }
  1112.  
  1113.  
  1114.  
  1115.  
  1116.  
  1117. //---------------------------------------------------------------------
  1118. //
  1119. // Function:   ShowPrintError
  1120. //
  1121. // Purpose:    Decode a printing error and display a message box
  1122. //             which describes what the error is.
  1123. //
  1124. //             Errors are stored in a bitwise fashion, so we
  1125. //             check all the valid error bits in the error, and
  1126. //             display a messagebox for each error.
  1127. //
  1128. // Parms:      hWnd   == Parent for message box which shows error.
  1129. //             wError == Error bitfield (see ERR_PRN_* in PRINT.H).
  1130. //
  1131. // History:   Date      Reason
  1132. //            11/14/91  Created
  1133. //
  1134. //---------------------------------------------------------------------
  1135.  
  1136. void ShowPrintError (HWND hWnd, DWORD dwError)
  1137. {
  1138.    char szError[100];
  1139.    int  i = 0;
  1140.  
  1141.    if (dwError == ERR_PRN_NONE)
  1142.       {
  1143.       if (LoadString (hInst, IDS_PRN_NONE, szError, 100))
  1144.          MessageBox (hWnd, szError, NULL, MB_OK);
  1145.       return;
  1146.       }
  1147.  
  1148.    while (dwError)
  1149.       {
  1150.       i++;
  1151.  
  1152.       if (dwError & 1)
  1153.          {
  1154.          if (LoadString (hInst, i + IDS_PRN_NONE, szError, 100))
  1155.             MessageBox (hWnd, szError, NULL, MB_OK);
  1156.          else
  1157.             MessageBeep (0);
  1158.          }
  1159.  
  1160.       dwError >>= 1;
  1161.       }
  1162. }
  1163.  
  1164.  
  1165.  
  1166.