emf.c
上传用户:yuandong
上传日期:2022-08-08
资源大小:954k
文件大小:84k
源码类别:

Delphi控件源码

开发平台:

C++ Builder

  1. /*++
  2. Copyright (c) 1990-1998  Microsoft Corporation
  3. All rights reserved
  4. Abstract:
  5.     Routines to facilitate printing of EMF jobs.
  6. --*/
  7. #include "local.h"
  8. #include "stddef.h"
  9. #include <windef.h>
  10. #include <messages.h>
  11. #include <winppi.h>
  12. #define EMF_DUP_NONE 0
  13. #define EMF_DUP_VERT 1
  14. #define EMF_DUP_HORZ 2
  15. #define EMF_DEGREE_90  1
  16. #define EMF_DEGREE_270 2
  17. //   PAGE_NUMBER is used to save a list of the page numbers to start new sides while
  18. //   Reverse Printing.
  19. typedef struct _PAGE_NUMBER {
  20.     struct _PAGE_NUMBER *pNext;
  21.     DWORD  dwPageNumber;
  22. } PAGE_NUMBER, *PPAGE_NUMBER;
  23. typedef struct _UpdateRect {
  24.         double  top;
  25.         double  bottom;
  26.         double  left;
  27.         double  right;
  28. }  UpdateRect;
  29. // The update factors for the different nup options. These factors when multiplied
  30. // with the horizontal and vertical resolutions give the coordinates for the rectangle
  31. // where the EMF page is to be played.
  32. UpdateRect URect21[] = {{0, 0.5, 0, 1},
  33.                         {0.5, 1, 0, 1}};
  34. UpdateRect URect21R[] = {{0.5, 1, 0, 1},
  35.                          {0, 0.5, 0, 1}};
  36. UpdateRect URect22[] = {{0, 1, 0, 0.5},
  37.                         {0, 1, 0.5, 1}};
  38. UpdateRect URect4[] = {{0, 0.5, 0, 0.5},
  39.                        {0, 0.5, 0.5, 1},
  40.                        {0.5, 1, 0, 0.5},
  41.                        {0.5, 1, 0.5, 1}};
  42. UpdateRect URect61[] = {{0, 1.0/3.0, 0, 0.5},
  43.                         {0, 1.0/3.0, 0.5, 1},
  44.                         {1.0/3.0, 2.0/3.0, 0, 0.5},
  45.                         {1.0/3.0, 2.0/3.0, 0.5, 1},
  46.                         {2.0/3.0, 1, 0, 0.5},
  47.                         {2.0/3.0, 1, 0.5, 1}};
  48. UpdateRect URect61R[] = {{2.0/3.0, 1, 0, 0.5},
  49.                          {1.0/3.0, 2.0/3.0, 0, 0.5},
  50.                          {0, 1.0/3.0, 0, 0.5},
  51.                          {2.0/3.0, 1, 0.5, 1},
  52.                          {1.0/3.0, 2.0/3.0, 0.5, 1},
  53.                          {0, 1.0/3.0, 0.5, 1}};
  54. UpdateRect URect62[]  = {{0, 0.5, 0, 1.0/3.0},
  55.                          {0, 0.5, 1.0/3.0, 2.0/3.0},
  56.                          {0, 0.5, 2.0/3.0, 1},
  57.                          {0.5, 1, 0, 1.0/3.0},
  58.                          {0.5, 1, 1.0/3.0, 2.0/3.0},
  59.                          {0.5, 1, 2.0/3.0, 1}};
  60. UpdateRect URect62R[] = {{0.5, 1, 0, 1.0/3.0},
  61.                          {0, 0.5, 0, 1.0/3.0},
  62.                          {0.5, 1, 1.0/3.0, 2.0/3.0},
  63.                          {0, 0.5, 1.0/3.0, 2.0/3.0},
  64.                          {0.5, 1, 2.0/3.0, 1},
  65.                          {0, 0.5, 2.0/3.0, 1}};
  66. UpdateRect URect9[] = {{0, 1.0/3.0, 0, 1.0/3.0},
  67.                        {0, 1.0/3.0, 1.0/3.0, 2.0/3.0},
  68.                        {0, 1.0/3.0, 2.0/3.0, 1},
  69.                        {1.0/3.0, 2.0/3.0, 0, 1.0/3.0},
  70.                        {1.0/3.0, 2.0/3.0, 1.0/3.0, 2.0/3.0},
  71.                        {1.0/3.0, 2.0/3.0, 2.0/3.0, 1},
  72.                        {2.0/3.0, 1, 0, 1.0/3.0},
  73.                        {2.0/3.0, 1, 1.0/3.0, 2.0/3.0},
  74.                        {2.0/3.0, 1, 2.0/3.0, 1}};
  75. UpdateRect URect16[] = {{0, 0.25, 0, 0.25},
  76.                         {0, 0.25, 0.25, 0.5},
  77.                         {0, 0.25, 0.5, 0.75},
  78.                         {0, 0.25, 0.75, 1},
  79.                         {0.25, 0.5, 0, 0.25},
  80.                         {0.25, 0.5, 0.25, 0.5},
  81.                         {0.25, 0.5, 0.5, 0.75},
  82.                         {0.25, 0.5, 0.75, 1},
  83.                         {0.5, 0.75, 0, 0.25},
  84.                         {0.5, 0.75, 0.25, 0.5},
  85.                         {0.5, 0.75, 0.5, 0.75},
  86.                         {0.5, 0.75, 0.75, 1},
  87.                         {0.75, 1, 0, 0.25},
  88.                         {0.75, 1, 0.25, 0.5},
  89.                         {0.75, 1, 0.5, 0.75},
  90.                         {0.75, 1, 0.75, 1}};
  91. BOOL
  92. ValidNumberForNUp(
  93.     DWORD  dwPages)
  94. /*++
  95. Function Description: Checks if the number of pages printed on a single side is Valid.
  96. Parameters: dwPages - Number of pages printed on a single side
  97. Return Values: TRUE if (dwPages = 1|2|4|6|9|16)
  98.                FALSE otherwise.
  99. --*/
  100. {
  101.     return ((dwPages == 1) || (dwPages == 2) || (dwPages == 4) ||
  102.             (dwPages == 6) || (dwPages == 9) || (dwPages == 16));
  103. }
  104. VOID
  105. GetPageCoordinatesForNUp(
  106.     HDC    hPrinterDC,
  107.     RECT   *rectDocument,
  108.     RECT   *rectBorder,
  109.     DWORD  dwTotalNumberOfPages,
  110.     UINT   uCurrentPageNumber,
  111.     DWORD  dwNupBorderFlags,
  112.     LPBOOL pbRotate
  113.     )
  114. /*++
  115. Function Description: GetPageCoordinatesForNUp computes the rectangle on the Page where the
  116.                       EMF file is to be played. It also determines if the picture is to
  117.                       rotated.
  118. Parameters:  hPrinterDC           - Printer Device Context
  119.              *rectDocument        - pointer to RECT where the coordinates to play the
  120.                                      page will be returned.
  121.              *rectBorder          - pointer to RECT where the page borders are to drawn.
  122.              dwTotalNumberOfPages - Total number of pages on 1 side.
  123.              uCurrentPageNumber   - 1 based page number on the side.
  124.              dwNupBorderFlags     - flags to draw border along logical pages.
  125.              pbRotate             - pointer to BOOL which indicates if the picture must be
  126.                                     rotated.
  127. Return Values:  NONE.
  128. --*/
  129. {
  130.     UpdateRect  *URect;
  131.     LONG        lXPrintPage,lYPrintPage,lXPhyPage,lYPhyPage,lXFrame,lYFrame,ltemp,ldX,ldY;
  132.     LONG        lXNewPhyPage,lYNewPhyPage,lXOffset,lYOffset,lNumRowCol,lRowIndex,lColIndex;
  133.     double      dXleft,dXright,dYtop,dYbottom;
  134.     LONG        xResolution = GetDeviceCaps(hPrinterDC, LOGPIXELSX);
  135.     LONG        yResolution = GetDeviceCaps(hPrinterDC, LOGPIXELSY);
  136.     // Get the 0-based array index for the current page
  137.     uCurrentPageNumber = uCurrentPageNumber - 1;
  138.     if (dwTotalNumberOfPages==1 || xResolution==yResolution)
  139.     {
  140.         xResolution = yResolution = 1;
  141.     }
  142.     rectDocument->top = rectDocument->bottom = lYPrintPage = (GetDeviceCaps(hPrinterDC, DESKTOPVERTRES)-1) * xResolution;
  143.     rectDocument->left = rectDocument->right = lXPrintPage = (GetDeviceCaps(hPrinterDC, DESKTOPHORZRES)-1) * yResolution;
  144.     lXPhyPage = GetDeviceCaps(hPrinterDC, PHYSICALWIDTH)  * yResolution;
  145.     lYPhyPage = GetDeviceCaps(hPrinterDC, PHYSICALHEIGHT) * xResolution;
  146.     *pbRotate = FALSE;
  147.     // Select the array containing the update factors
  148.     switch (dwTotalNumberOfPages) {
  149.     case 1: rectDocument->top = rectDocument->left = 0;
  150.             rectDocument->right += 1;
  151.             rectDocument->bottom += 1;
  152.             return;
  153.     case 2: if (lXPrintPage > lYPrintPage) {  // cut vertically
  154.                 URect = URect22;
  155.                 lXFrame = (LONG) (lXPrintPage / 2.0);
  156.                 lYFrame = lYPrintPage;
  157.             } else {                          // cut horizontally
  158.                 URect = URect21;
  159.                 lYFrame = (LONG) (lYPrintPage / 2.0);
  160.                 lXFrame = lXPrintPage;
  161.             }
  162.             break;
  163.     case 4: URect = URect4;
  164.             lXFrame = (LONG) (lXPrintPage / 2.0);
  165.             lYFrame = (LONG) (lYPrintPage / 2.0);
  166.             break;
  167.     case 6: if (lXPrintPage > lYPrintPage) {  // cut vertically twice
  168.                 URect = URect62;
  169.                 lXFrame = (LONG) (lXPrintPage / 3.0);
  170.                 lYFrame = (LONG) (lYPrintPage / 2.0);
  171.             } else {                          // cut horizontally twice
  172.                 URect = URect61;
  173.                 lYFrame = (LONG) (lYPrintPage / 3.0);
  174.                 lXFrame = (LONG) (lXPrintPage / 2.0);
  175.             }
  176.             break;
  177.     case 9: URect = URect9;
  178.             lXFrame = (LONG) (lXPrintPage / 3.0);
  179.             lYFrame = (LONG) (lYPrintPage / 3.0);
  180.             break;
  181.     case 16: URect = URect16;
  182.              lXFrame = (LONG) (lXPrintPage / 4.0);
  183.              lYFrame = (LONG) (lYPrintPage / 4.0);
  184.              break;
  185.     default: // Should Not Occur.
  186.              return;
  187.     }
  188.     // Set the flag if the picture has to be rotated
  189.     *pbRotate = !((lXPhyPage >= lYPhyPage) && (lXFrame >= lYFrame)) &&
  190.                 !((lXPhyPage < lYPhyPage) && (lXFrame < lYFrame));
  191.     // If the picture is to be rotated, modify the rectangle selected.
  192.     if ((dwTotalNumberOfPages == 2) || (dwTotalNumberOfPages == 6)) {
  193.        if (*pbRotate) {
  194.           switch (dwTotalNumberOfPages) {
  195.           case 2: if (lXPrintPage <= lYPrintPage) {
  196.                       URect = URect21R;
  197.                   } // URect22 = URect22R
  198.                   break;
  199.           case 6: if (lXPrintPage <= lYPrintPage) {
  200.                       URect = URect61R;
  201.                   } else {
  202.                       URect = URect62R;
  203.                   }
  204.                   break;
  205.           }
  206.        }
  207.     } else {
  208.        if (*pbRotate) {
  209.           // get the number of rows/columns. switch is faster than sqrt.
  210.           switch (dwTotalNumberOfPages) {
  211.           case 4: lNumRowCol = 2;
  212.                   break;
  213.           case 9: lNumRowCol = 3;
  214.                   break;
  215.           case 16: lNumRowCol = 4;
  216.                   break;
  217.           }
  218.           lRowIndex  = (LONG) (uCurrentPageNumber / lNumRowCol);
  219.           lColIndex  = (LONG) (uCurrentPageNumber % lNumRowCol);
  220.           uCurrentPageNumber = (lNumRowCol - 1 - lColIndex) * lNumRowCol + lRowIndex;
  221.        }
  222.     }
  223.     // Update the Page Coordinates.
  224.     rectDocument->top    = (LONG) (rectDocument->top    * URect[uCurrentPageNumber].top);
  225.     rectDocument->bottom = (LONG) (rectDocument->bottom * URect[uCurrentPageNumber].bottom);
  226.     rectDocument->left   = (LONG) (rectDocument->left   * URect[uCurrentPageNumber].left);
  227.     rectDocument->right  = (LONG) (rectDocument->right  * URect[uCurrentPageNumber].right);
  228.     // If the page border has to drawn, return the corresponding coordinates in rectBorder.
  229.     if (dwNupBorderFlags == BORDER_PRINT) {
  230.         rectBorder->top    = rectDocument->top/xResolution;
  231.         rectBorder->bottom = rectDocument->bottom/xResolution - 1;
  232.         rectBorder->left   = rectDocument->left/yResolution;
  233.         rectBorder->right  = rectDocument->right/yResolution - 1;
  234.     }
  235.     if (*pbRotate) {
  236.         ltemp = lXFrame; lXFrame = lYFrame; lYFrame = ltemp;
  237.     }
  238.     // Get the new size of the rectangle to keep the X/Y ratio constant.
  239.     if ( ((LONG) (lYFrame*((lXPhyPage*1.0)/lYPhyPage))) >= lXFrame) {
  240.          ldX = 0;
  241.          ldY = lYFrame - ((LONG) (lXFrame*((lYPhyPage*1.0)/lXPhyPage)));
  242.     } else {
  243.          ldY = 0;
  244.          ldX = lXFrame - ((LONG) (lYFrame*((lXPhyPage*1.0)/lYPhyPage)));
  245.     }
  246.     // Adjust the position of the rectangle.
  247.     if (*pbRotate) {
  248.         if (ldX) {
  249.             rectDocument->bottom -= (LONG) (ldX / 2.0);
  250.             rectDocument->top    += (LONG) (ldX / 2.0);
  251.         } else {
  252.            rectDocument->right   -= (LONG) (ldY / 2.0);
  253.            rectDocument->left    += (LONG) (ldY / 2.0);
  254.         }
  255.     } else {
  256.         if (ldX) {
  257.            rectDocument->left    += (LONG) (ldX / 2.0);
  258.            rectDocument->right   -= (LONG) (ldX / 2.0);
  259.         } else {
  260.            rectDocument->top     += (LONG) (ldY / 2.0);
  261.            rectDocument->bottom  -= (LONG) (ldY / 2.0);
  262.         }
  263.     }
  264.     // Adjust to get the Printable Area on the rectangle
  265.     lXOffset = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETX) * yResolution;
  266.     lYOffset = GetDeviceCaps(hPrinterDC, PHYSICALOFFSETY) * xResolution;
  267.     dXleft = ( lXOffset * 1.0) / lXPhyPage;
  268.     dYtop  = ( lYOffset * 1.0) / lYPhyPage;
  269.     dXright =  ((lXPhyPage - (lXOffset + lXPrintPage)) * 1.0) / lXPhyPage;
  270.     dYbottom = ((lYPhyPage - (lYOffset + lYPrintPage)) * 1.0) / lYPhyPage;
  271.     lXNewPhyPage = rectDocument->right  - rectDocument->left;
  272.     lYNewPhyPage = rectDocument->bottom - rectDocument->top;
  273.     if (*pbRotate) {
  274.        ltemp = lXNewPhyPage; lXNewPhyPage = lYNewPhyPage; lYNewPhyPage = ltemp;
  275.        rectDocument->left   += (LONG) (dYtop    * lYNewPhyPage);
  276.        rectDocument->right  -= (LONG) (dYbottom * lYNewPhyPage);
  277.        rectDocument->top    += (LONG) (dXright  * lXNewPhyPage);
  278.        rectDocument->bottom -= (LONG) (dXleft   * lXNewPhyPage);
  279.     } else {
  280.        rectDocument->left   += (LONG) (dXleft   * lXNewPhyPage);
  281.        rectDocument->right  -= (LONG) (dXright  * lXNewPhyPage);
  282.        rectDocument->top    += (LONG) (dYtop    * lYNewPhyPage);
  283.        rectDocument->bottom -= (LONG) (dYbottom * lYNewPhyPage);
  284.     }
  285.     if (xResolution!=yResolution)
  286.     {
  287.         rectDocument->left   = rectDocument->left   / yResolution;
  288.         rectDocument->right  = rectDocument->right  / yResolution;
  289.         rectDocument->top    = rectDocument->top    / xResolution;
  290.         rectDocument->bottom = rectDocument->bottom / xResolution;
  291.     }
  292.     return;
  293. }
  294. BOOL
  295. PlayEMFPage(
  296.     HANDLE       hSpoolHandle,
  297.     HDC          hPrinterDC,
  298.     HANDLE       hEMF,
  299.     DWORD        dwNumberOfPagesPerSide,
  300.     DWORD        dwPageNumber,
  301.     DWORD        dwPageIndex,
  302.     DWORD        dwNupBorderFlags,
  303.     DWORD        dwAngle)
  304. /*++
  305. Function Description: PlayEMFPage plays the EMF in the appropriate rectangle. It performs
  306.                       the required scaling, rotation and translation.
  307. Parameters:   hSpoolHandle           -- handle the spool file handle
  308.               hPrinterDC             -- handle to the printer device context
  309.               hEMF                   -- handle to the contents of the page in the spool file
  310.               dwNumberOfPagesPerSide -- number of pages to be printed per side
  311.               dwPageNumber           -- page number in the document
  312.               dwPageIndex            -- page number in the side. (1 based)
  313.               dwNupBorderFlags       -- border printing options for nup
  314.               dwAngle                -- angle for rotation (if neccesary)
  315. Return Values:  TRUE if successful
  316.                 FALSE otherwise
  317. --*/
  318. {
  319.    BOOL         bReturn = FALSE, bRotate;
  320.    RECT         rectDocument, rectPrinter, rectBorder = {-1, -1, -1, -1};
  321.    RECT         *prectClip = NULL;
  322.    XFORM        TransXForm = {1, 0, 0, 1, 0, 0}, RotateXForm = {0, -1, 1, 0, 0, 0};
  323.    HPEN         hPen;
  324.    HANDLE       hFormEMF;
  325.    DWORD        dwPageType,dwFormPage;
  326.    // Compute the rectangle for one page.
  327.    GetPageCoordinatesForNUp(hPrinterDC,
  328.                             &rectDocument,
  329.                             &rectBorder,
  330.                             dwNumberOfPagesPerSide,
  331.                             dwPageIndex,
  332.                             dwNupBorderFlags,
  333.                             &bRotate);
  334.    if (dwAngle == EMF_DEGREE_270) {
  335.        RotateXForm.eM12 = 1;
  336.        RotateXForm.eM21 = -1;
  337.    }   // EMF_DEGREE_90 case is the initialization
  338.    if (bRotate) {
  339.        rectPrinter.top = 0;
  340.        rectPrinter.bottom = rectDocument.right - rectDocument.left;
  341.        rectPrinter.left = 0;
  342.        rectPrinter.right = rectDocument.bottom - rectDocument.top;
  343.        // Set the translation matrix
  344.        if (dwAngle == EMF_DEGREE_270) {
  345.            TransXForm.eDx = (float) rectDocument.right;
  346.            TransXForm.eDy = (float) rectDocument.top;
  347.        } else {
  348.            // EMF_DEGREE_90
  349.            TransXForm.eDx = (float) rectDocument.left;
  350.            TransXForm.eDy = (float) rectDocument.bottom;
  351.        }
  352.        // Set the transformation matrix
  353.        if (!SetWorldTransform(hPrinterDC, &RotateXForm) ||
  354.            !ModifyWorldTransform(hPrinterDC, &TransXForm, MWT_RIGHTMULTIPLY)) {
  355.             ODS(("Setting transformation matrix failedn"));
  356.             goto CleanUp;
  357.        }
  358.    }
  359.    // Add clipping for Nup
  360.    if (dwNumberOfPagesPerSide != 1) {
  361.        prectClip = &rectDocument;
  362.    }
  363.    // Print the page.
  364.    if (bRotate) {
  365.        GdiPlayPageEMF(hSpoolHandle, hEMF, &rectPrinter, &rectBorder, prectClip);
  366.    } else {
  367.        GdiPlayPageEMF(hSpoolHandle, hEMF, &rectDocument, &rectBorder, prectClip);
  368.    }
  369.    bReturn = TRUE;
  370. CleanUp:
  371.    if (!ModifyWorldTransform(hPrinterDC, NULL, MWT_IDENTITY)) {
  372.        ODS(("Setting Identity Transformation failedn"));
  373.        bReturn = FALSE;
  374.    }
  375.    return bReturn;
  376. }
  377. BOOL
  378. SetDrvCopies(
  379.     HDC          hPrinterDC,
  380.     LPDEVMODEW   pDevmode,
  381.     DWORD        dwNumberOfCopies)
  382. /*++
  383. Function Description: SetDrvCopies sets the dmCopies field in pDevmode and resets
  384.                       hPrinterDC with this devmode
  385. Parameters: hPrinterDC             -- handle to the printer device context
  386.             pDevmode               -- pointer to devmode
  387.             dwNumberOfCopies       -- value for dmCopies
  388. Return Values:  TRUE if successful
  389.                 FALSE otherwise
  390. --*/
  391. {
  392.     BOOL     bReturn;
  393.     DWORD    dmFields;
  394.     if ((pDevmode->dmFields & DM_COPIES) &&
  395.         (pDevmode->dmCopies == (short) dwNumberOfCopies)) {
  396.          return TRUE;
  397.     }
  398.     // Save the old fields structure
  399.     dmFields = pDevmode->dmFields;
  400.     pDevmode->dmFields |= DM_COPIES;
  401.     pDevmode->dmCopies = (short) dwNumberOfCopies;
  402.     if (!ResetDC(hPrinterDC, pDevmode))  {
  403.         bReturn = FALSE;
  404.     } else {
  405.         bReturn = TRUE;
  406.     }
  407.     // Restore the fields structure
  408.     pDevmode->dmFields = dmFields;
  409.     if (!SetGraphicsMode(hPrinterDC,GM_ADVANCED)) {
  410.         ODS(("Setting graphics mode failedn"));
  411.         bReturn = FALSE;
  412.     }
  413.     return bReturn;
  414. }
  415. BOOL
  416. DifferentDevmodes(
  417.     LPDEVMODE    pDevmode1,
  418.     LPDEVMODE    pDevmode2
  419.     )
  420. /*++
  421. Function Description: Compares the devmodes for differences other than dmTTOption
  422. Parameters:  pDevmode1    -   devmode 1
  423.              pDevmode2    -   devmode 2
  424. Return Values: TRUE if different ; FALSE otherwise
  425. --*/
  426. {
  427.     DWORD   dwSize1, dwSize2, dwTTOffset, dwSpecOffset, dwLogOffset;
  428.     // Same pointers are the same devmode
  429.     if (pDevmode1 == pDevmode2) {
  430.         return FALSE;
  431.     }
  432.     // Check for Null devmodes
  433.     if (!pDevmode1 || !pDevmode2) {
  434.         return TRUE;
  435.     }
  436.     dwSize1 = pDevmode1->dmSize + pDevmode1->dmDriverExtra;
  437.     dwSize2 = pDevmode2->dmSize + pDevmode2->dmDriverExtra;
  438.     // Compare devmode sizes
  439.     if (dwSize1 != dwSize2) {
  440.         return TRUE;
  441.     }
  442.     dwTTOffset = FIELD_OFFSET(DEVMODE, dmTTOption);
  443.     dwSpecOffset = FIELD_OFFSET(DEVMODE, dmSpecVersion);
  444.     dwLogOffset = FIELD_OFFSET(DEVMODE, dmLogPixels);
  445.     if (wcscmp(pDevmode1->dmDeviceName,
  446.                pDevmode2->dmDeviceName)) {
  447.         // device names are different
  448.         return TRUE;
  449.     }
  450.     if (dwTTOffset < dwSpecOffset ||
  451.         dwSize1 < dwLogOffset) {
  452.         // incorrent devmode offsets
  453.         return TRUE;
  454.     }
  455.     if (memcmp((LPBYTE) pDevmode1 + dwSpecOffset,
  456.                (LPBYTE) pDevmode2 + dwSpecOffset,
  457.                dwTTOffset - dwSpecOffset)) {
  458.         // Front half is different
  459.         return TRUE;
  460.     }
  461.     // Ignore the dmTTOption setting.
  462.     if ((pDevmode1->dmCollate != pDevmode2->dmCollate) ||
  463.         wcscmp(pDevmode1->dmFormName, pDevmode2->dmFormName)) {
  464.         // form name or collate option is different
  465.         return TRUE;
  466.     }
  467.     if (memcmp((LPBYTE) pDevmode1 + dwLogOffset,
  468.                (LPBYTE) pDevmode2 + dwLogOffset,
  469.                dwSize1 - dwLogOffset)) {
  470.         // Back half is different
  471.         return TRUE;
  472.     }
  473.     return FALSE;
  474. }
  475. BOOL
  476. ResetDCForNewDevmode(
  477.     HANDLE       hSpoolHandle,
  478.     HDC          hPrinterDC,
  479.     DWORD        dwPageNumber,
  480.     BOOL         bInsidePage,
  481.     DWORD        dwOptimization,
  482.     LPBOOL       pbNewDevmode,
  483.     LPDEVMODE    pDevmode
  484.     )
  485. /*++
  486. Function Description: Determines if the devmode for the page is different from the
  487.                       current devmode for the printer dc and resets the dc if necessary.
  488.                       The parameters allow dmTTOption to be ignored in devmode comparison.
  489. Parameters: hSpoolHandle         -  spool file handle
  490.             hPrinterDC           -  printer dc
  491.             dwPageNumber         -  page number before which we search for the devmode
  492.             bInsidePage          -  flag to ignore changes in TT options and call EndPage
  493.                                        before ResetDC
  494.             dwOptimization       -  optimization flags
  495.             pbNewDevmode         -  pointer to flag to indicate if ResetDC was called
  496.             pDevmode             -  devmode containing changed resolution settings
  497. Return Values: TRUE if successful; FALSE otherwise
  498. --*/
  499. {
  500.     BOOL           bReturn = FALSE;
  501.     LPDEVMODE      pLastDM, pCurrDM;
  502.     // Initialize OUT parameters
  503.     *pbNewDevmode = FALSE;
  504.     // Get the devmode just before the page
  505.     if (!GdiGetDevmodeForPage(hSpoolHandle,
  506.                               dwPageNumber,
  507.                               &pCurrDM,
  508.                               &pLastDM)) {
  509.         ODS(("GdiGetDevmodeForPage failedn"));
  510.         return bReturn;
  511.     }
  512.     // Check if the devmodes are different
  513.     if (pLastDM != pCurrDM) {
  514.         // If the pointers are different the devmodes are always different
  515.         if (!bInsidePage ||
  516.             DifferentDevmodes(pLastDM, pCurrDM)) {
  517.             *pbNewDevmode = TRUE;
  518.         }
  519.     }
  520.     // Call ResetDC on the hPrinterDC if necessary
  521.     if (*pbNewDevmode) {
  522.         if (bInsidePage &&
  523.             !GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  524.             ODS(("EndPage failedn"));
  525.             return bReturn;
  526.         }
  527.         if (pCurrDM) {
  528.             pCurrDM->dmPrintQuality = pDevmode->dmPrintQuality;
  529.             pCurrDM->dmYResolution = pDevmode->dmYResolution;
  530.         }
  531.         // Ignore the return values of ResetDC and SetGraphicsMode
  532.         GdiResetDCEMF(hSpoolHandle, pCurrDM);
  533.         SetGraphicsMode(hPrinterDC, GM_ADVANCED);
  534.     }
  535.     bReturn = TRUE;
  536.     return bReturn;
  537. }
  538. DWORD
  539. PrintOneSideForwardEMF(
  540.     HANDLE       hSpoolHandle,
  541.     HDC          hPrinterDC,
  542.     DWORD        dwNumberOfPagesPerSide,
  543.     DWORD        dwDrvNumberOfPagesPerSide,
  544.     DWORD        dwNupBorderFlags,
  545.     BOOL         bDuplex,
  546.     DWORD        dwOptimization,
  547.     DWORD        dwPageNumber,
  548.     LPBOOL       pbComplete,
  549.     LPDEVMODE    pDevmode)
  550. /*++
  551. Function Description: PrintOneSideForwardEMF plays the next physical page in the same order
  552.                       as the spool file.
  553. Parameters: hSpoolHandle              -- handle the spool file handle
  554.             hPrinterDC                -- handle to the printer device context
  555.             dwNumberOfPagesPerSide    -- number of pages to be printed per side by the print processor
  556.             dwDrvNumberOfPagesPerSide -- number of pages the driver will print per side
  557.             dwNupBorderFlags          -- border printing options for nup
  558.             bDuplex                   -- flag to indicate duplex printing
  559.             dwOptimization            -- optimization flags
  560.             dwPageNumber              -- pointer to the starting page number
  561.             pbComplete                -- pointer to the flag to indicate completion
  562.             pDevmode                  -- devmode with resolution settings
  563. Return Values:  Last Page Number if successful
  564.                 0 on job completion (pbReturn set to TRUE) and
  565.                   on failure (pbReturn remains FALSE)
  566. --*/
  567. {
  568.     DWORD              dwPageIndex, dwPageType;
  569.     DWORD              dwReturn = 0;
  570.     LPDEVMODEW         pLastDM, pCurrDM;
  571.     HANDLE             hEMF = NULL;
  572.     DWORD              dwSides;
  573.     BOOL               bNewDevmode;
  574.     DWORD              cPagesToPlay;
  575.     // set the number of sides on this page;
  576.     dwSides = bDuplex ? 2 : 1;
  577.     *pbComplete = FALSE;
  578.     for ( ; dwSides && !*pbComplete ; --dwSides) {
  579.        // loop for a single side
  580.        for (dwPageIndex = 1;
  581.             dwPageIndex <= dwNumberOfPagesPerSide;
  582.             ++dwPageIndex, ++dwPageNumber) {
  583.             if (!(hEMF = GdiGetPageHandle(hSpoolHandle,
  584.                                           dwPageNumber,
  585.                                           &dwPageType))) {
  586.                 if (GetLastError() == ERROR_NO_MORE_ITEMS) {
  587.                      // End of the print job
  588.                      *pbComplete = TRUE;
  589.                      break;
  590.                 }
  591.                 ODS(("GdiGetPageHandle failednPrinter %wsn", pDevmode->dmDeviceName));
  592.                 goto CleanUp;
  593.             }
  594.             // Process new devmodes in the spool file that appear before this page
  595.             if (!ResetDCForNewDevmode(hSpoolHandle,
  596.                                       hPrinterDC,
  597.                                       dwPageNumber,
  598.                                       (dwPageIndex != 1),
  599.                                       dwOptimization,
  600.                                       &bNewDevmode,
  601.                                       pDevmode)) {
  602.                 goto CleanUp;
  603.             }
  604.             // Reset page index if new page was started
  605.             if (bNewDevmode) {
  606.                 dwPageIndex = 1;
  607.             }
  608.             // Call StartPage for each new page
  609.             if ((dwPageIndex == 1) &&
  610.                 !GdiStartPageEMF(hSpoolHandle)) {
  611.                 ODS(("StartPage failednPrinter %wsn", pDevmode->dmDeviceName));
  612.                 goto CleanUp;
  613.             }
  614.             if (!PlayEMFPage(hSpoolHandle,
  615.                              hPrinterDC,
  616.                              hEMF,
  617.                              dwNumberOfPagesPerSide,
  618.                              dwPageNumber,
  619.                              dwPageIndex,
  620.                              dwNupBorderFlags,
  621.                              EMF_DEGREE_90)) {
  622.                 ODS(("PlayEMFPage failednPrinter %wsn", pDevmode->dmDeviceName));
  623.                 goto CleanUp;
  624.             }
  625.        }
  626.        //
  627.        // Explaination of the scinario set for the conditions on
  628.        // dwPageIndex1 , pbComplete and bDuplex.
  629.        // N.B. we are naming them cond.1 and cond.2
  630.        //     dwPageIndex!=1    pbComplete   bDuplex    Condition
  631.        //           0               0           0       None
  632.        //           0               0           1       None
  633.        //           0               1           0       None
  634.        //           0               1           1       Cond2 on Second Side i.e. dwsides==1
  635.        //           1               0           0       Cond1
  636.        //           1               0           1       Cond1
  637.        //           1               1           0       Cond1
  638.        //           1               1           1       Cond1 & Cond2 on First Side i.e. dwsides==2
  639.        //
  640.        // cond.1
  641.        if (dwPageIndex != 1) {
  642.            // Call EndPage if we played any pages
  643.            if (!GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  644.                ODS(("EndPage failedn"));
  645.                *pbComplete = FALSE;
  646.                goto CleanUp;
  647.            }
  648.        }
  649.        // cond.2
  650.        // play empty page on the back of duplex
  651.        if (*pbComplete && bDuplex && dwDrvNumberOfPagesPerSide==1) {
  652.            ODS(("PCL or PS with no N-upn"));
  653.            //
  654.            // Checking dwsides against 2 or 1.
  655.            // depends on whether it is n-up or not.
  656.            //
  657.            if (((dwPageIndex!=1)?(dwSides==2):(dwSides==1))) {
  658.                if (!GdiStartPageEMF(hSpoolHandle) ||
  659.                    !GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  660.                    ODS(("EndPage failedn"));
  661.                    *pbComplete = FALSE;
  662.                    goto CleanUp;
  663.                }
  664.            }
  665.         }
  666.     }
  667.     if (*pbComplete &&
  668.         dwNumberOfPagesPerSide==1 &&
  669.         dwDrvNumberOfPagesPerSide!=1 &&
  670.         bDuplex &&
  671.         (dwPageNumber-1)%(2*dwDrvNumberOfPagesPerSide))
  672.     {
  673.         //
  674.         // Number of pages played on last phisical page
  675.         //
  676.         cPagesToPlay = 2*dwDrvNumberOfPagesPerSide - (dwPageNumber-1)%(2*dwDrvNumberOfPagesPerSide);
  677.         ODS(("nPS with N-up!nMust fill in %u pagesn", cPagesToPlay));
  678.         for (;cPagesToPlay;cPagesToPlay--)
  679.         {
  680.             if (!GdiStartPageEMF(hSpoolHandle) || !GdiEndPageEMF(hSpoolHandle, dwOptimization))
  681.             {
  682.                 ODS(("EndPage failedn"));
  683.                 goto CleanUp;
  684.             }
  685.         }
  686.     }
  687.     if (!(*pbComplete)) dwReturn = dwPageNumber;
  688. CleanUp:
  689.     return dwReturn;
  690. }
  691. BOOL
  692. PrintForwardEMF(
  693.     HANDLE       hSpoolHandle,
  694.     HDC          hPrinterDC,
  695.     DWORD        dwNumberOfPagesPerSide,
  696.     DWORD        dwDrvNumberOfPagesPerSide,
  697.     DWORD        dwNupBorderFlags,
  698.     DWORD        dwJobNumberOfCopies,
  699.     DWORD        dwDrvNumberOfCopies,
  700.     BOOL         bCollate,
  701.     BOOL         bDuplex,
  702.     DWORD        dwOptimization,
  703.     LPDEVMODEW   pDevmode,
  704.     PPRINTPROCESSORDATA pData)
  705. /*++
  706. Function Description: PrintForwardEMF plays the EMF files in the order in which they
  707.                       were spooled.
  708. Parameters: hSpoolHandle              -- handle the spool file handle
  709.             hPrinterDC                -- handle to the printer device context
  710.             dwNumberOfPagesPerSide    -- number of pages to be printed per side by the print processor
  711.             dwDrvNumberOfPagesPerSide -- number of pages the driver will print per side
  712.             dwNupBorderFlags          -- border printing options for nup
  713.             dwJobNumberOfCopies       -- number of copies of the job to be printed
  714.             dwDrvNumberOfCopies       -- number of copies that the driver can print
  715.             bCollate                  -- flag for collating the copies
  716.             bDuplex                   -- flag for duplex printing
  717.             dwOptimization            -- optimization flags
  718.             pDevmode                  -- pointer to devmode for changing the copy count
  719.             pData                     -- needed for status and the handle of the event: pause, resume etc.
  720. Return Values:  TRUE if successful
  721.                 FALSE otherwise
  722. --*/
  723. {
  724.     DWORD              dwLastPageNumber = 1,dwPageNumber,dwPageIndex,dwRemainingCopies;
  725.     BOOL               bReturn = FALSE;
  726.     // Keep printing as long as the spool file contains EMF handles.
  727.     while (dwLastPageNumber) {
  728.         //
  729.         // If the print processor is paused, wait for it to be resumed
  730.         //
  731.         if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  732.             WaitForSingleObject(pData->semPaused, INFINITE);
  733.         }
  734.         dwPageNumber = dwLastPageNumber;
  735.         if (bCollate) {
  736.            dwLastPageNumber = PrintOneSideForwardEMF(hSpoolHandle,
  737.                                                      hPrinterDC,
  738.                                                      dwNumberOfPagesPerSide,
  739.                                                      dwDrvNumberOfPagesPerSide,
  740.                                                      dwNupBorderFlags,
  741.                                                      bDuplex,
  742.                                                      dwOptimization,
  743.                                                      dwPageNumber,
  744.                                                      &bReturn,
  745.                                                      pDevmode);
  746.         } else {
  747.            dwRemainingCopies = dwJobNumberOfCopies;
  748.            while (dwRemainingCopies) {
  749.                if (dwRemainingCopies <= dwDrvNumberOfCopies) {
  750.                   SetDrvCopies(hPrinterDC, pDevmode, dwRemainingCopies);
  751.                   dwRemainingCopies = 0;
  752.                } else {
  753.                   SetDrvCopies(hPrinterDC, pDevmode, dwDrvNumberOfCopies);
  754.                   dwRemainingCopies -= dwDrvNumberOfCopies;
  755.                }
  756.                //
  757.                // If the print processor is paused, wait for it to be resumed
  758.                //
  759.                if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  760.                     WaitForSingleObject(pData->semPaused, INFINITE);
  761.                }
  762.                if (!(dwLastPageNumber =  PrintOneSideForwardEMF(hSpoolHandle,
  763.                                                                 hPrinterDC,
  764.                                                                 dwNumberOfPagesPerSide,
  765.                                                                 dwDrvNumberOfPagesPerSide,
  766.                                                                 dwNupBorderFlags,
  767.                                                                 bDuplex,
  768.                                                                 dwOptimization,
  769.                                                                 dwPageNumber,
  770.                                                                 &bReturn,
  771.                                                                 pDevmode)) &&
  772.                    !bReturn) {
  773.                     goto CleanUp;
  774.                }
  775.            }
  776.         }
  777.     }
  778. CleanUp:
  779.     return bReturn;
  780. }
  781. BOOL
  782. PrintOneSideReverseForDriverEMF(
  783.     HANDLE       hSpoolHandle,
  784.     HDC          hPrinterDC,
  785.     DWORD        dwDrvNumberOfPagesPerSide,
  786.     DWORD        dwTotalNumberOfPages,
  787.     DWORD        dwNupBorderFlags,
  788.     BOOL         bDuplex,
  789.     DWORD        dwOptimization,
  790.     DWORD        dwPageNumber,
  791.     LPDEVMODE    pDevmode)
  792. /*++
  793. Function Description: PrintOneSideReverseForDriverEMF plays the EMF pages on the next
  794.                       physical page, in the reverse order for the driver which does the
  795.                       Nup transformations.
  796. Parameters: hSpoolHandle           -- handle the spool file handle
  797.             hPrinterDC             -- handle to the printer device context
  798.             dwDrvNumberOfPagesPerSide -- number of pages the driver will print per side
  799.             dwTotalNumberOfPages   -- total number of pages in the document
  800.             dwNupBorderFlags       -- border printing options for nup
  801.             bDuplex                -- flag to indicate duplex printing
  802.             dwOptimization         -- optimization flags
  803.             dwPageNumber           -- page number to start the side
  804.             pDevmode               -- devmode with resolution settings
  805. Return Values:  TRUE if successful
  806.                 FALSE otherwise
  807. --*/
  808. {
  809.     DWORD       dwPageIndex, dwPageType, dwSides;
  810.     BOOL        bReturn = FALSE, bNewDevmode,BeSmart;
  811.     LPDEVMODEW  pLastDM,pCurrDM;
  812.     HANDLE      hEMF = NULL;
  813.     DWORD       dwLimit;
  814.     dwSides = bDuplex ? 2 : 1;
  815.     //
  816.     // If the document will fit on one phisical page, then this variable will prevent
  817.     // the printer from playing extra pages just to fill in one phisical page
  818.     // The exception is when the pages fit on a single phisical page, but they must
  819.     // be collated. Then because of design, the printer will also draw borders for the
  820.     // empty pages which are played so that the page gets ejected.
  821.     //
  822.     BeSmart =  (dwTotalNumberOfPages<=dwDrvNumberOfPagesPerSide) &&
  823.                (pDevmode->dmCollate != DMCOLLATE_TRUE);
  824.     for (; dwSides; --dwSides) {
  825.        // This loop may play some empty pages in the last side, since the
  826.        // driver is doing nup and it does not keep count of the page numbers
  827.        //
  828.        dwPageIndex=BeSmart?dwPageNumber:1;
  829.        dwLimit    =BeSmart?dwTotalNumberOfPages:dwDrvNumberOfPagesPerSide;
  830.        for (;dwPageIndex<=dwLimit; ++dwPageIndex,++dwPageNumber) {
  831.              if (BeSmart || dwPageNumber <= dwTotalNumberOfPages) {
  832.                  if (!(hEMF = GdiGetPageHandle(hSpoolHandle,
  833.                                                dwPageNumber,
  834.                                                &dwPageType))) {
  835.                      ODS(("GdiGetPageHandle failednPrinter %wsn", pDevmode->dmDeviceName));
  836.                      goto CleanUp;
  837.                  }
  838.                  // Process new devmodes in the spoolfile
  839.                  if (!ResetDCForNewDevmode(hSpoolHandle,
  840.                                            hPrinterDC,
  841.                                            dwPageNumber,
  842.                                            FALSE,
  843.                                            dwOptimization,
  844.                                            &bNewDevmode,
  845.                                            pDevmode)) {
  846.                  }
  847.              }
  848.              if (!GdiStartPageEMF(hSpoolHandle)) {
  849.                  ODS(("StartPage failednPrinter %wsn", pDevmode->dmDeviceName));
  850.                  goto CleanUp;
  851.              }
  852.              if (BeSmart || dwPageNumber <= dwTotalNumberOfPages) {
  853.                 if (!PlayEMFPage(hSpoolHandle,
  854.                                   hPrinterDC,
  855.                                   hEMF,
  856.                                   1,
  857.                                   dwPageNumber,
  858.                                   1,
  859.                                   dwNupBorderFlags,
  860.                                   EMF_DEGREE_90)) {
  861.                      ODS(("PlayEMFPage failedn"));
  862.                      goto CleanUp;
  863.                  }
  864.              }
  865.              if (!GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  866.                  ODS(("EndPage failednPrinter %wsn", pDevmode->dmDeviceName));
  867.                  goto CleanUp;
  868.              }
  869.        }
  870.     }
  871.     bReturn = TRUE;
  872. CleanUp:
  873.     return bReturn;
  874. }
  875. BOOL
  876. PrintReverseForDriverEMF(
  877.     HANDLE     hSpoolHandle,
  878.     HDC        hPrinterDC,
  879.     DWORD      dwDrvNumberOfPagesPerSide,
  880.     DWORD      dwTotalNumberOfPages,
  881.     DWORD      dwNupBorderFlags,
  882.     DWORD      dwJobNumberOfCopies,
  883.     DWORD      dwDrvNumberOfCopies,
  884.     BOOL       bCollate,
  885.     BOOL       bDuplex,
  886.     BOOL       bOdd,
  887.     DWORD      dwOptimization,
  888.     LPDEVMODEW pDevmode,
  889.     PPAGE_NUMBER pHead,
  890.     PPRINTPROCESSORDATA pData)
  891. /*++
  892. Function Description: PrintReverseForDriverEMF plays the EMF pages in the reverse order
  893.                       for the driver which does the Nup transformations.
  894. Parameters: hSpoolHandle           -- handle the spool file handle
  895.             hPrinterDC             -- handle to the printer device context
  896.             dwDrvNumberOfPagesPerSide -- number of pages the driver will print per side
  897.             dwTotalNumberOfPages   -- total number of pages in the document
  898.             dwNupBorderFlags       -- border printing options for nup
  899.             dwJobNumberOfCopies    -- number of copies of the job to be printed
  900.             dwDrvNumberOfCopies    -- number of copies that the driver can print
  901.             bCollate               -- flag for collating the copies
  902.             bDuplex                -- flag to indicate duplex printing
  903.             bOdd                   -- flag to indicate odd number of sides to print
  904.             dwOptimization         -- optimization flags
  905.             pDevmode               -- pointer to devmode for changing the copy count
  906.             pHead                  -- pointer to a linked list containing the starting
  907.                                        page numbers for each of the sides
  908.             pData                  -- needed for status and the handle of the event: pause, resume etc.
  909. Return Values:  TRUE if successful
  910.                 FALSE otherwise
  911. --*/
  912. {
  913.     DWORD         dwPageIndex,dwPageNumber,dwRemainingCopies;
  914.     BOOL          bReturn = FALSE;
  915.     // select the correct page for duplex printing
  916.     if (bDuplex && !bOdd) {
  917.        if (pHead) {
  918.           pHead = pHead->pNext;
  919.        } else {
  920.           bReturn = TRUE;
  921.           goto CleanUp;
  922.        }
  923.     }
  924.     // play the sides in reverse order
  925.     while (pHead) {
  926.         //
  927.         // If the print processor is paused, wait for it to be resumed
  928.         //
  929.         if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  930.             WaitForSingleObject(pData->semPaused, INFINITE);
  931.         }
  932.         // set the page number
  933.         dwPageNumber = pHead->dwPageNumber;
  934.         if (bCollate) {
  935.            if (!PrintOneSideReverseForDriverEMF(hSpoolHandle,
  936.                                                 hPrinterDC,
  937.                                                 dwDrvNumberOfPagesPerSide,
  938.                                                 dwTotalNumberOfPages,
  939.                                                 dwNupBorderFlags,
  940.                                                 bDuplex,
  941.                                                 dwOptimization,
  942.                                                 dwPageNumber,
  943.                                                 pDevmode)) {
  944.                goto CleanUp;
  945.            }
  946.         } else {
  947.            dwRemainingCopies = dwJobNumberOfCopies;
  948.            while (dwRemainingCopies) {
  949.                if (dwRemainingCopies <= dwDrvNumberOfCopies) {
  950.                   SetDrvCopies(hPrinterDC, pDevmode, dwRemainingCopies);
  951.                   dwRemainingCopies = 0;
  952.                } else {
  953.                   SetDrvCopies(hPrinterDC, pDevmode, dwDrvNumberOfCopies);
  954.                   dwRemainingCopies -= dwDrvNumberOfCopies;
  955.                }
  956.                if (!PrintOneSideReverseForDriverEMF(hSpoolHandle,
  957.                                                     hPrinterDC,
  958.                                                     dwDrvNumberOfPagesPerSide,
  959.                                                     dwTotalNumberOfPages,
  960.                                                     dwNupBorderFlags,
  961.                                                     bDuplex,
  962.                                                     dwOptimization,
  963.                                                     dwPageNumber,
  964.                                                     pDevmode)) {
  965.                    goto CleanUp;
  966.                }
  967.            }
  968.         }
  969.         pHead = pHead->pNext;
  970.         // go to the next page for duplex printing
  971.         if (bDuplex && pHead) {
  972.             pHead = pHead->pNext;
  973.         }
  974.     }
  975.     bReturn = TRUE;
  976. CleanUp:
  977.     return bReturn;
  978. }
  979. BOOL
  980. PrintOneSideReverseEMF(
  981.     HANDLE       hSpoolHandle,
  982.     HDC          hPrinterDC,
  983.     DWORD        dwNumberOfPagesPerSide,
  984.     DWORD        dwNupBorderFlags,
  985.     BOOL         bDuplex,
  986.     DWORD        dwOptimization,
  987.     DWORD        dwStartPage1,
  988.     DWORD        dwEndPage1,
  989.     DWORD        dwStartPage2,
  990.     DWORD        dwEndPage2,
  991.     LPDEVMODE    pDevmode)
  992. /*++
  993. Function Description: PrintOneSideReverseEMF plays the EMF pages for the next physical page.
  994. Parameters: hSpoolHandle           -- handle the spool file handle
  995.             hPrinterDC             -- handle to the printer device context
  996.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  997.                                        processor
  998.             dwNupBorderFlags       -- border printing options for nup
  999.             bDuplex                -- flag to indicate duplex printing
  1000.             dwOptimization         -- optimization flags
  1001.             dwStartPage1           -- page number of the first EMF page on 1st side
  1002.             dwEndPage1             -- page number of the last EMF page on 1st side
  1003.             dwStartPage2           -- page number of the first EMF page on 2nd side
  1004.             dwEndPage2             -- page number of the last EMF page on 2nd side
  1005.             pDevmode               -- devmode with resolution settings
  1006. Return Values:  TRUE if successful
  1007.                 FALSE otherwise
  1008. --*/
  1009. {
  1010.     DWORD         dwPageNumber, dwPageIndex, dwPageType;
  1011.     BOOL          bReturn = FALSE, bNewDevmode;
  1012.     LPDEVMODEW    pLastDM,pCurrDM;
  1013.     HANDLE        hEMF = NULL;
  1014.     DWORD         dwEndPage, dwStartPage, dwSides;
  1015.     for (dwSides = bDuplex ? 2 : 1;
  1016.          dwSides;
  1017.          --dwSides) {
  1018.          if (bDuplex && (dwSides == 1)) {
  1019.              dwStartPage = dwStartPage2;
  1020.              dwEndPage = dwEndPage2;
  1021.          } else {
  1022.              dwStartPage = dwStartPage1;
  1023.              dwEndPage = dwEndPage1;
  1024.          }
  1025.          for (dwPageNumber = dwStartPage, dwPageIndex = 1;
  1026.               dwPageNumber <= dwEndPage;
  1027.               ++dwPageNumber, ++dwPageIndex) {
  1028.                if (!(hEMF = GdiGetPageHandle(hSpoolHandle,
  1029.                                              dwPageNumber,
  1030.                                              &dwPageType))) {
  1031.                     ODS(("GdiGetPageHandle failednPrinter %wsn", pDevmode->dmDeviceName));
  1032.                     goto CleanUp;
  1033.                }
  1034.                if (dwPageIndex == 1) {
  1035.                    // Process devmodes in the spool file and call StartPage
  1036.                    if (!ResetDCForNewDevmode(hSpoolHandle,
  1037.                                              hPrinterDC,
  1038.                                              dwPageNumber,
  1039.                                              FALSE,
  1040.                                              dwOptimization,
  1041.                                              &bNewDevmode,
  1042.                                              pDevmode) ||
  1043.                        !GdiStartPageEMF(hSpoolHandle)) {
  1044.                        goto CleanUp;
  1045.                    }
  1046.                }
  1047.                if (!PlayEMFPage(hSpoolHandle,
  1048.                                 hPrinterDC,
  1049.                                 hEMF,
  1050.                                 dwNumberOfPagesPerSide,
  1051.                                 dwPageNumber,
  1052.                                 dwPageIndex,
  1053.                                 dwNupBorderFlags,
  1054.                                 EMF_DEGREE_90)) {
  1055.                    ODS(("PlayEMFPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1056.                    goto CleanUp;
  1057.                }
  1058.          }
  1059.          if ((dwPageIndex == 1) && !GdiStartPageEMF(hSpoolHandle)) {
  1060.               ODS(("StartPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1061.               goto CleanUp;
  1062.          }
  1063.          if (!GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  1064.              ODS(("EndPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1065.              goto CleanUp;
  1066.          }
  1067.     }
  1068.     bReturn = TRUE;
  1069. CleanUp:
  1070.     return bReturn;
  1071. }
  1072. BOOL
  1073. PrintReverseEMF(
  1074.     HANDLE       hSpoolHandle,
  1075.     HDC          hPrinterDC,
  1076.     DWORD        dwTotalNumberOfPages,
  1077.     DWORD        dwNumberOfPagesPerSide,
  1078.     DWORD        dwNupBorderFlags,
  1079.     DWORD        dwJobNumberOfCopies,
  1080.     DWORD        dwDrvNumberOfCopies,
  1081.     BOOL         bCollate,
  1082.     BOOL         bDuplex,
  1083.     BOOL         bOdd,
  1084.     DWORD        dwOptimization,
  1085.     LPDEVMODEW   pDevmode,
  1086.     PPAGE_NUMBER pHead,
  1087.     PPRINTPROCESSORDATA pData)
  1088. /*++
  1089. Function Description: PrintReverseEMF plays the EMF pages in the reverse order and also
  1090.                       performs nup transformations.
  1091. Parameters: hSpoolHandle           -- handle the spool file handle
  1092.             hPrinterDC             -- handle to the printer device context
  1093.             dwTotalNumberOfPages   -- number of pages in the document
  1094.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  1095.                                        processor
  1096.             dwNupBorderFlags       -- border printing options for nup
  1097.             dwJobNumberOfCopies    -- number of copies of the job to be printed
  1098.             dwDrvNumberOfCopies    -- number of copies that the driver can print
  1099.             bCollate               -- flag for collating the copies
  1100.             bDuplex                -- flag to indicate duplex printing
  1101.             bOdd                   -- flag to indicate odd number of sides to print
  1102.             dwOptimization         -- optimization flags
  1103.             pDevmode               -- pointer to devmode for changing the copy count
  1104.             pHead                  -- pointer to a linked list containing the starting
  1105.                                        page numbers for each of the sides
  1106.             pData                  -- needed for status and the handle of the event: pause, resume etc.
  1107. Return Values:  TRUE if successful
  1108.                 FALSE otherwise
  1109. --*/
  1110. {
  1111.     DWORD         dwPageNumber,dwPageIndex,dwRemainingCopies;
  1112.     DWORD         dwStartPage1,dwStartPage2,dwEndPage1,dwEndPage2;
  1113.     BOOL          bReturn = FALSE;
  1114.     if (!pHead) {
  1115.         bReturn = TRUE;
  1116.         goto CleanUp;
  1117.     }
  1118.     // set the start and end page numbers for duplex and regular printing
  1119.     if (bDuplex) {
  1120.        if (bOdd) {
  1121.            dwStartPage1 = pHead->dwPageNumber;
  1122.            dwEndPage1   = dwTotalNumberOfPages;
  1123.            dwStartPage2 = dwTotalNumberOfPages+1;
  1124.            dwEndPage2   = 0;
  1125.        } else {
  1126.            dwStartPage2 = pHead->dwPageNumber;
  1127.            dwEndPage2   = dwTotalNumberOfPages;
  1128.            if (pHead = pHead->pNext) {
  1129.                dwStartPage1 = pHead->dwPageNumber;
  1130.                dwEndPage1   = dwStartPage2 - 1;
  1131.            }
  1132.        }
  1133.     } else {
  1134.        dwStartPage1 = pHead->dwPageNumber;
  1135.        dwEndPage1   = dwTotalNumberOfPages;
  1136.        dwStartPage2 = 0;
  1137.        dwEndPage2   = 0;
  1138.     }
  1139.     while (pHead) {
  1140.        //
  1141.        // If the print processor is paused, wait for it to be resumed
  1142.        //
  1143.        if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  1144.               WaitForSingleObject(pData->semPaused, INFINITE);
  1145.        }
  1146.        if (bCollate) {
  1147.           if (!PrintOneSideReverseEMF(hSpoolHandle,
  1148.                                       hPrinterDC,
  1149.                                       dwNumberOfPagesPerSide,
  1150.                                       dwNupBorderFlags,
  1151.                                       bDuplex,
  1152.                                       dwOptimization,
  1153.                                       dwStartPage1,
  1154.                                       dwEndPage1,
  1155.                                       dwStartPage2,
  1156.                                       dwEndPage2,
  1157.                                       pDevmode)) {
  1158.               goto CleanUp;
  1159.           }
  1160.        } else {
  1161.           dwRemainingCopies = dwJobNumberOfCopies;
  1162.           while (dwRemainingCopies) {
  1163.               if (dwRemainingCopies <= dwDrvNumberOfCopies) {
  1164.                  SetDrvCopies(hPrinterDC, pDevmode, dwRemainingCopies);
  1165.                  dwRemainingCopies = 0;
  1166.               } else {
  1167.                  SetDrvCopies(hPrinterDC, pDevmode, dwDrvNumberOfCopies);
  1168.                  dwRemainingCopies -= dwDrvNumberOfCopies;
  1169.               }
  1170.               if (!PrintOneSideReverseEMF(hSpoolHandle,
  1171.                                           hPrinterDC,
  1172.                                           dwNumberOfPagesPerSide,
  1173.                                           dwNupBorderFlags,
  1174.                                           bDuplex,
  1175.                                           dwOptimization,
  1176.                                           dwStartPage1,
  1177.                                           dwEndPage1,
  1178.                                           dwStartPage2,
  1179.                                           dwEndPage2,
  1180.                                           pDevmode)) {
  1181.                   goto CleanUp;
  1182.               }
  1183.           }
  1184.        }
  1185.        if (bDuplex) {
  1186.           if (pHead->pNext && pHead->pNext->pNext) {
  1187.               dwEndPage2 = pHead->dwPageNumber - 1;
  1188.               pHead = pHead->pNext;
  1189.               dwStartPage2 = pHead->dwPageNumber;
  1190.               dwEndPage1 = dwStartPage2 - 1;
  1191.               pHead = pHead->pNext;
  1192.               dwStartPage1 = pHead->dwPageNumber;
  1193.           } else {
  1194.               break;
  1195.           }
  1196.        } else {
  1197.           pHead = pHead->pNext;
  1198.           if (pHead) {
  1199.               dwEndPage1 = dwStartPage1 - 1;
  1200.               dwStartPage1 = pHead->dwPageNumber;
  1201.           }
  1202.        }
  1203.     }
  1204.     bReturn = TRUE;
  1205. CleanUp:
  1206.     return bReturn;
  1207. }
  1208. BOOL
  1209. PrintOneSideBookletEMF(
  1210.     HANDLE       hSpoolHandle,
  1211.     HDC          hPrinterDC,
  1212.     DWORD        dwNumberOfPagesPerSide,
  1213.     DWORD        dwNupBorderFlags,
  1214.     DWORD        dwTotalNumberOfPages,
  1215.     DWORD        dwTotalPrintPages,
  1216.     DWORD        dwStartPage,
  1217.     BOOL         bReverseOrderPrinting,
  1218.     DWORD        dwOptimization,
  1219.     DWORD        dwDuplexMode,
  1220.     LPDEVMODE    pDevmode)
  1221. /*++
  1222. Function Description: PrintOneSideBookletEMF prints one page of the booklet job.
  1223. Parameters: hSpoolHandle           -- handle the spool file handle
  1224.             hPrinterDC             -- handle to the printer device context
  1225.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  1226.                                        processor
  1227.             dwNupBorderFlags       -- border printing options for nup
  1228.             dwTotalNumberOfPages   -- number of pages in the document
  1229.             dwTotalPrintPages      -- number of pages to printed (multiple of 4)
  1230.             dwStartPage            -- number of the starting page for the side
  1231.             bReverseOrderPrinting  -- flag for reverse order printing
  1232.             dwOptimization         -- optimization flags
  1233.             dwDuplexMode           -- duplex printing mode (none|horz|vert)
  1234.             pDevmode               -- devmode with resolution settings
  1235. Return Values:  TRUE if successful
  1236.                 FALSE otherwise
  1237. --*/
  1238. {
  1239.     DWORD       dwPageArray[4];
  1240.     DWORD       dwPagesPrinted = 0, dwPageIndex, dwAngle, dwPageType, dwLastPage;
  1241.     HANDLE      hEMF = NULL;
  1242.     LPDEVMODEW  pLastDM, pCurrDM;
  1243.     BOOL        bReturn = FALSE ,bNewDevmode;
  1244.     // set the order of the pages
  1245.     if (bReverseOrderPrinting) {
  1246.         dwPageArray[0] = dwStartPage + 1;
  1247.         dwPageArray[1] = dwTotalPrintPages - dwStartPage;
  1248.         if (dwDuplexMode == EMF_DUP_VERT) {
  1249.            dwPageArray[2] = dwStartPage;
  1250.            dwPageArray[3] = dwPageArray[1] + 1;
  1251.         } else { // EMF_DUP_HORZ
  1252.            dwPageArray[3] = dwStartPage;
  1253.            dwPageArray[2] = dwPageArray[1] + 1;
  1254.         }
  1255.     } else {
  1256.         dwPageArray[1] = dwStartPage;
  1257.         dwPageArray[0] = dwTotalPrintPages - dwStartPage + 1;
  1258.         if (dwDuplexMode == EMF_DUP_VERT) {
  1259.            dwPageArray[2] = dwPageArray[0] - 1;
  1260.            dwPageArray[3] = dwPageArray[1] + 1;
  1261.         } else { // EMF_DUP_HORZ
  1262.            dwPageArray[2] = dwPageArray[1] + 1;
  1263.            dwPageArray[3] = dwPageArray[0] - 1;
  1264.         }
  1265.     }
  1266.     // Set page number for ResetDC
  1267.     dwLastPage = (dwTotalNumberOfPages < dwPageArray[0]) ? dwTotalNumberOfPages
  1268.                                                          : dwPageArray[0];
  1269.     // Process devmodes in the spool file
  1270.     if (!ResetDCForNewDevmode(hSpoolHandle,
  1271.                               hPrinterDC,
  1272.                               dwLastPage,
  1273.                               FALSE,
  1274.                               dwOptimization,
  1275.                               &bNewDevmode,
  1276.                               pDevmode)) {
  1277.         goto CleanUp;
  1278.     }
  1279.     while (dwPagesPrinted < 4) {
  1280.        for (dwPageIndex = 1;
  1281.             dwPageIndex <= dwNumberOfPagesPerSide;
  1282.             ++dwPageIndex, ++dwPagesPrinted) {
  1283.             if (dwPageArray[dwPagesPrinted] <= dwTotalNumberOfPages) {
  1284.                 if (!(hEMF = GdiGetPageHandle(hSpoolHandle,
  1285.                                               dwPageArray[dwPagesPrinted],
  1286.                                               &dwPageType))) {
  1287.                      ODS(("GdiGetPageHandle failednPrinter %wsn", pDevmode->dmDeviceName));
  1288.                      goto CleanUp;
  1289.                 }
  1290.             }
  1291.             if (dwPageIndex == 1) {
  1292.                if (!GdiStartPageEMF(hSpoolHandle)) {
  1293.                    ODS(("StartPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1294.                    goto CleanUp;
  1295.                }
  1296.             }
  1297.             if (dwPageArray[dwPagesPrinted] <= dwTotalNumberOfPages) {
  1298.                  if ((dwDuplexMode == EMF_DUP_VERT) &&
  1299.                      (dwPagesPrinted > 1)) {
  1300.                       dwAngle = EMF_DEGREE_270;
  1301.                  } else { // EMF_DUP_HORZ or 1st side
  1302.                       dwAngle = EMF_DEGREE_90;
  1303.                  }
  1304.                  if (!PlayEMFPage(hSpoolHandle,
  1305.                                   hPrinterDC,
  1306.                                   hEMF,
  1307.                                   dwNumberOfPagesPerSide,
  1308.                                   dwPageArray[dwPagesPrinted],
  1309.                                   dwPageIndex,
  1310.                                   dwNupBorderFlags,
  1311.                                   dwAngle)) {
  1312.                      ODS(("PlayEMFPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1313.                      goto CleanUp;
  1314.                  }
  1315.             }
  1316.             if (dwPageIndex == dwNumberOfPagesPerSide) {
  1317.                 if (!GdiEndPageEMF(hSpoolHandle, dwOptimization)) {
  1318.                      ODS(("EndPage failednPrinter %wsn", pDevmode->dmDeviceName));
  1319.                      goto CleanUp;
  1320.                 }
  1321.             }
  1322.        }
  1323.     }
  1324.     bReturn = TRUE;
  1325. CleanUp:
  1326.     return bReturn;
  1327. }
  1328. BOOL
  1329. PrintBookletEMF(
  1330.     HANDLE       hSpoolHandle,
  1331.     HDC          hPrinterDC,
  1332.     DWORD        dwNumberOfPagesPerSide,
  1333.     DWORD        dwTotalNumberOfPages,
  1334.     DWORD        dwNupBorderFlags,
  1335.     DWORD        dwJobNumberOfCopies,
  1336.     DWORD        dwDrvNumberOfCopies,
  1337.     BOOL         bReverseOrderPrinting,
  1338.     BOOL         bCollate,
  1339.     DWORD        dwOptimization,
  1340.     DWORD        dwDuplexMode,
  1341.     LPDEVMODEW   pDevmode,
  1342.     PPRINTPROCESSORDATA pData)
  1343. /*++
  1344. Function Description: PrintBookletEMF prints the job in 2-up in booklet form.
  1345. Parameters: hSpoolHandle           -- handle the spool file handle
  1346.             hPrinterDC             -- handle to the printer device context
  1347.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  1348.                                        processor
  1349.             dwTotalNumberOfPages   -- number of pages in the document
  1350.             dwNupBorderFlags       -- border printing options for nup
  1351.             dwJobNumberOfCopies    -- number of copies of the job to be printed
  1352.             dwDrvNumberOfCopies    -- number of copies that the driver can print
  1353.             bReverseOrderPrinting  -- flag for reverse order printing
  1354.             bCollate               -- flag for collating the copies
  1355.             dwOptimization         -- optimization flags
  1356.             dwDuplexMode           -- duplex printing mode (none|horz|vert)
  1357.             pDevmode               -- pointer to devmode for changing the copy count
  1358.             pData                  -- needed for status and the handle of the event: pause, resume etc.
  1359. Return Values:  TRUE if successful
  1360.                 FALSE otherwise
  1361. --*/
  1362. {
  1363.     BOOL              bReturn = FALSE;
  1364.     DWORD             dwTotalPrintPages, dwNumberOfPhyPages, dwRemainingCopies, dwIndex;
  1365.     // Get closest multiple of 4 greater than dwTotalNumberOfPages
  1366.     dwTotalPrintPages = dwTotalNumberOfPages - (dwTotalNumberOfPages % 4);
  1367.     if (dwTotalPrintPages != dwTotalNumberOfPages) {
  1368.         dwTotalPrintPages += 4;
  1369.     }
  1370.     dwNumberOfPhyPages = (DWORD) dwTotalPrintPages / 4;
  1371.     for (dwIndex = 0; dwIndex < dwNumberOfPhyPages; ++dwIndex) {
  1372.          //
  1373.          // If the print processor is paused, wait for it to be resumed
  1374.          //
  1375.          if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  1376.                 WaitForSingleObject(pData->semPaused, INFINITE);
  1377.          }
  1378.          if (bCollate) {
  1379.             if (!PrintOneSideBookletEMF(hSpoolHandle,
  1380.                                         hPrinterDC,
  1381.                                         dwNumberOfPagesPerSide,
  1382.                                         dwNupBorderFlags,
  1383.                                         dwTotalNumberOfPages,
  1384.                                         dwTotalPrintPages,
  1385.                                         dwIndex * 2 + 1,
  1386.                                         bReverseOrderPrinting,
  1387.                                         dwOptimization,
  1388.                                         dwDuplexMode,
  1389.                                         pDevmode)) {
  1390.                  goto CleanUp;
  1391.             }
  1392.          } else {
  1393.             dwRemainingCopies = dwJobNumberOfCopies;
  1394.             while (dwRemainingCopies) {
  1395.                 if (dwRemainingCopies <= dwDrvNumberOfCopies) {
  1396.                    SetDrvCopies(hPrinterDC, pDevmode, dwRemainingCopies);
  1397.                    dwRemainingCopies = 0;
  1398.                 } else {
  1399.                    SetDrvCopies(hPrinterDC, pDevmode, dwDrvNumberOfCopies);
  1400.                    dwRemainingCopies -= dwDrvNumberOfCopies;
  1401.                 }
  1402.                 if (!PrintOneSideBookletEMF(hSpoolHandle,
  1403.                                             hPrinterDC,
  1404.                                             dwNumberOfPagesPerSide,
  1405.                                             dwNupBorderFlags,
  1406.                                             dwTotalNumberOfPages,
  1407.                                             dwTotalPrintPages,
  1408.                                             dwIndex * 2 + 1,
  1409.                                             bReverseOrderPrinting,
  1410.                                             dwOptimization,
  1411.                                             dwDuplexMode,
  1412.                                             pDevmode)) {
  1413.                      goto CleanUp;
  1414.                 }
  1415.             }
  1416.          }
  1417.     }
  1418.     bReturn = TRUE;
  1419. CleanUp:
  1420.     return bReturn;
  1421. }
  1422. BOOL
  1423. PrintEMFSingleCopy(
  1424.     HANDLE       hSpoolHandle,
  1425.     HDC          hPrinterDC,
  1426.     BOOL         bReverseOrderPrinting,
  1427.     DWORD        dwDrvNumberOfPagesPerSide,
  1428.     DWORD        dwNumberOfPagesPerSide,
  1429.     DWORD        dwTotalNumberOfPages,
  1430.     DWORD        dwNupBorderFlags,
  1431.     DWORD        dwJobNumberOfCopies,
  1432.     DWORD        dwDrvNumberOfCopies,
  1433.     BOOL         bCollate,
  1434.     BOOL         bOdd,
  1435.     BOOL         bBookletPrint,
  1436.     DWORD        dwOptimization,
  1437.     DWORD        dwDuplexMode,
  1438.     LPDEVMODEW   pDevmode,
  1439.     PPAGE_NUMBER pHead,
  1440.     PPRINTPROCESSORDATA pData)
  1441. /*++
  1442. Function Description: PrintEMFSingleCopy plays one copy of the job on hPrinterDC.
  1443. Parameters: hSpoolHandle           -- handle the spool file handle
  1444.             hPrinterDC             -- handle to the printer device context
  1445.             bReverseOrderPrinting  -- flag for reverse order printing
  1446.             dwDrvNumberOfPagesPerSide -- number of pages the driver will print per side
  1447.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  1448.                                        processor
  1449.             dwTotalNumberOfPages   -- number of pages in the document
  1450.             dwNupBorderFlags       -- border printing options for nup
  1451.             dwJobNumberOfCopies    -- number of copies of the job to be printed
  1452.             dwDrvNumberOfCopies    -- number of copies that the driver can print
  1453.             bCollate               -- flag for collating the copies
  1454.             bOdd                   -- flag to indicate odd number of sides to print
  1455.             bBookletPrint          -- flag for booklet printing
  1456.             dwOptimization         -- optimization flags
  1457.             dwDuplexMode           -- duplex printing mode (none|horz|vert)
  1458.             pDevmode               -- pointer to devmode for changing the copy count
  1459.             pHead                  -- pointer to a linked list containing the starting
  1460.                                        page numbers for each of the sides
  1461.             pData                  -- needed for status and the handle of the event: pause, resume etc.
  1462. Return Values:  TRUE if successful
  1463.                 FALSE otherwise
  1464. --*/
  1465. {
  1466.     BOOL  bDuplex = (dwDuplexMode != EMF_DUP_NONE);
  1467.     if (bBookletPrint) {
  1468.        // Booklet Printing
  1469.        return PrintBookletEMF(hSpoolHandle,
  1470.                               hPrinterDC,
  1471.                               dwNumberOfPagesPerSide,
  1472.                               dwTotalNumberOfPages,
  1473.                               dwNupBorderFlags,
  1474.                               dwJobNumberOfCopies,
  1475.                               dwDrvNumberOfCopies,
  1476.                               bReverseOrderPrinting,
  1477.                               bCollate,
  1478.                               dwOptimization,
  1479.                               dwDuplexMode,
  1480.                               pDevmode,
  1481.                               pData);
  1482.     }
  1483.     if (bReverseOrderPrinting) {
  1484.        if (dwDrvNumberOfPagesPerSide != 1 || dwNumberOfPagesPerSide == 1) {
  1485.           return PrintReverseForDriverEMF(hSpoolHandle,
  1486.                                           hPrinterDC,
  1487.                                           dwDrvNumberOfPagesPerSide,
  1488.                                           dwTotalNumberOfPages,
  1489.                                           dwNupBorderFlags,
  1490.                                           dwJobNumberOfCopies,
  1491.                                           dwDrvNumberOfCopies,
  1492.                                           bCollate,
  1493.                                           bDuplex,
  1494.                                           bOdd,
  1495.                                           dwOptimization,
  1496.                                           pDevmode,
  1497.                                           pHead,
  1498.                                           pData);
  1499.        } else {
  1500.           // Reverse printing and nup
  1501.           return PrintReverseEMF(hSpoolHandle,
  1502.                                  hPrinterDC,
  1503.                                  dwTotalNumberOfPages,
  1504.                                  dwNumberOfPagesPerSide,
  1505.                                  dwNupBorderFlags,
  1506.                                  dwJobNumberOfCopies,
  1507.                                  dwDrvNumberOfCopies,
  1508.                                  bCollate,
  1509.                                  bDuplex,
  1510.                                  bOdd,
  1511.                                  dwOptimization,
  1512.                                  pDevmode,
  1513.                                  pHead,
  1514.                                  pData);
  1515.        }
  1516.     } else {
  1517.        // Normal printing
  1518.        return PrintForwardEMF(hSpoolHandle,
  1519.                               hPrinterDC,
  1520.                               dwNumberOfPagesPerSide,
  1521.                               dwDrvNumberOfPagesPerSide,
  1522.                               dwNupBorderFlags,
  1523.                               dwJobNumberOfCopies,
  1524.                               dwDrvNumberOfCopies,
  1525.                               bCollate,
  1526.                               bDuplex,
  1527.                               dwOptimization,
  1528.                               pDevmode,
  1529.                               pData);
  1530.     }
  1531. }
  1532. BOOL
  1533. GetStartPageList(
  1534.     HANDLE       hSpoolHandle,
  1535.     PPAGE_NUMBER *pHead,
  1536.     DWORD        dwTotalNumberOfPages,
  1537.     DWORD        dwNumberOfPagesPerSide,
  1538.     LPBOOL       pbOdd)
  1539. /*++
  1540. Function Description: GetStartPageList generates a list of the page numbers which
  1541.                       should appear on the start of each side of the job. This takes
  1542.                       into consideration the ResetDC calls that may appear before the
  1543.                       end of the page. The list generated by GetStartPageList is used
  1544.                       to play the job in reverse order.
  1545. Parameters: hSpoolHandle           -- handle the spool file handle
  1546.             pHead                  -- pointer to a pointer to a linked list containing the
  1547.                                        starting page numbers for each of the sides
  1548.             dwTotalNumberOfPages   -- number of pages in the document
  1549.             dwNumberOfPagesPerSide -- number of pages to be printed per side by the print
  1550.                                        processor
  1551.             pbOdd                  -- pointer to flag indicating odd number of pages to
  1552.                                        print
  1553. Return Values:  TRUE if successful
  1554.                 FALSE otherwise
  1555. --*/
  1556. {
  1557.     DWORD        dwPageIndex,dwPageNumber=1,dwPageType;
  1558.     LPDEVMODEW   pCurrDM, pLastDM;
  1559.     PPAGE_NUMBER pTemp=NULL;
  1560.     BOOL         bReturn = FALSE;
  1561.     BOOL         bCheckDevmode;
  1562.     bCheckDevmode = (dwNumberOfPagesPerSide != 1);
  1563.     while (dwPageNumber <= dwTotalNumberOfPages) {
  1564.        for (dwPageIndex = 1;
  1565.             (dwPageIndex <= dwNumberOfPagesPerSide) && (dwPageNumber <= dwTotalNumberOfPages);
  1566.             ++dwPageIndex, ++dwPageNumber) {
  1567.           if (bCheckDevmode) {
  1568.              // Check if the devmode has changed requiring a new page
  1569.              if (!GdiGetDevmodeForPage(hSpoolHandle, dwPageNumber,
  1570.                                                &pCurrDM, NULL)) {
  1571.                  ODS(("Get devmodes failedn"));
  1572.                  goto CleanUp;
  1573.              }
  1574.              if (dwPageIndex == 1) {
  1575.                  // Save the Devmode for the first page on a side
  1576.                  pLastDM = pCurrDM;
  1577.              } else {
  1578.                  // If the Devmode changes in a side, start a new page
  1579.                  if (DifferentDevmodes(pCurrDM, pLastDM)) {
  1580.                      dwPageIndex = 1;
  1581.                      pLastDM = pCurrDM;
  1582.                  }
  1583.              }
  1584.           }
  1585.           // Create a node for the start of a side
  1586.           if (dwPageIndex == 1) {
  1587.               if (!(pTemp = AllocSplMem(sizeof(PAGE_NUMBER)))) {
  1588.                   ODS(("GetStartPageList - Run out of memory"));
  1589.                   goto CleanUp;
  1590.               }
  1591.               pTemp->pNext = *pHead;
  1592.               pTemp->dwPageNumber = dwPageNumber;
  1593.               *pHead = pTemp;
  1594.               // flip the bOdd flag
  1595.               *pbOdd = !*pbOdd;
  1596.           }
  1597.        }
  1598.     }
  1599.     bReturn = TRUE;
  1600. CleanUp:
  1601.     // Free up the memory in case of a failure.
  1602.     if (!bReturn) {
  1603.        while (pTemp = *pHead) {
  1604.           *pHead = (*pHead)->pNext;
  1605.           FreeSplMem(pTemp);
  1606.        }
  1607.     }
  1608.     return bReturn;
  1609. }
  1610. BOOL
  1611. CopyDevmode(
  1612.     PPRINTPROCESSORDATA pData,
  1613.     LPDEVMODEW *pDevmode)
  1614. /*++
  1615. Function Description: Copies the devmode in pData or the default devmode into pDevmode.
  1616. Parameters:   pData           - Data structure for the print job
  1617.               pDevmode        - pointer to devmode
  1618. Return Value:  TRUE  if successful
  1619.                FALSE otherwise
  1620. --*/
  1621. {
  1622.     HANDLE           hDrvPrinter = NULL;
  1623.     BOOL             bReturn = FALSE;
  1624.     fnWinSpoolDrv    fnList;
  1625.     LONG             lNeeded;
  1626.     if (pData->pDevmode) {
  1627.         lNeeded = pData->pDevmode->dmSize +  pData->pDevmode->dmDriverExtra;
  1628.         if (*pDevmode = (LPDEVMODEW) AllocSplMem(lNeeded)) {
  1629.             memcpy(*pDevmode, pData->pDevmode, lNeeded);
  1630.         } else {
  1631.             goto CleanUp;
  1632.         }
  1633.     } else {
  1634.         // Get the default devmode
  1635.         // Get the pointer to the client side functions from the router
  1636.         if (!SplInitializeWinSpoolDrv(&fnList)) {
  1637.             goto CleanUp;
  1638.         }
  1639.         // Get a client side printer handle to pass to the driver
  1640.         if (!(* (fnList.pfnOpenPrinter))(pData->pPrinterName, &hDrvPrinter, NULL)) {
  1641.             ODS(("Open printer failednPrinter %wsn", pData->pPrinterName));
  1642.             goto CleanUp;
  1643.         }
  1644.         lNeeded = (* (fnList.pfnDocumentProperties))(NULL,
  1645.                                                      hDrvPrinter,
  1646.                                                      pData->pPrinterName,
  1647.                                                      NULL,
  1648.                                                      NULL,
  1649.                                                      0);
  1650.         if (lNeeded <= 0  ||
  1651.             !(*pDevmode = (LPDEVMODEW) AllocSplMem(lNeeded)) ||
  1652.             (* (fnList.pfnDocumentProperties))(NULL,
  1653.                                                hDrvPrinter,
  1654.                                                pData->pPrinterName,
  1655.                                                *pDevmode,
  1656.                                                NULL,
  1657.                                                DM_OUT_BUFFER) < 0) {
  1658.              if (*pDevmode) {
  1659.                 FreeSplMem(*pDevmode);
  1660.                 *pDevmode = NULL;
  1661.              }
  1662.              ODS(("DocumentProperties failednPrinter %wsn",pData->pPrinterName));
  1663.              goto CleanUp;
  1664.         }
  1665.     }
  1666.     bReturn = TRUE;
  1667. CleanUp:
  1668.     if (hDrvPrinter) {
  1669.         (* (fnList.pfnClosePrinter))(hDrvPrinter);
  1670.     }
  1671.     return bReturn;
  1672. }
  1673. BOOL
  1674. PrintEMFJob(
  1675.     PPRINTPROCESSORDATA pData,
  1676.     LPWSTR pDocumentName)
  1677. /*++
  1678. Function Description: Prints out a job with EMF data type.
  1679. Parameters:   pData           - Data structure for this job
  1680.               pDocumentName   - Name of this document
  1681. Return Value:  TRUE  if successful
  1682.                FALSE if failed - GetLastError() will return reason.
  1683. --*/
  1684. {
  1685.     HANDLE             hSpoolHandle = NULL;
  1686.     HDC                hPrinterDC = NULL;
  1687.     BOOL               bReverseOrderPrinting, bReturn = FALSE, bSetWorldXform = TRUE;
  1688.     BOOL               bCollate, bDuplex, bBookletPrint, bStartDoc = FALSE, bOdd = FALSE;
  1689.     DWORD              dwNumberOfPagesPerSide, dwTotalNumberOfPages = 0, dwNupBorderFlags;
  1690.     DWORD              dwJobNumberOfPagesPerSide, dwDrvNumberOfPagesPerSide, dwDuplexMode;
  1691.     DWORD              dwJobNumberOfCopies, dwDrvNumberOfCopies,dwRemainingCopies;
  1692.     DWORD              dwJobOrder, dwDrvOrder, dwOptimization;
  1693.     DOCINFOW           DocInfo;
  1694.     XFORM              OldXForm;
  1695.     PPAGE_NUMBER       pHead = NULL,pTemp;
  1696.     ATTRIBUTE_INFO_3   AttributeInfo;
  1697.     LPDEVMODEW         pDevmode = NULL, pFirstDM = NULL, pCopyDM;
  1698.     // Copy the devmode into pDevMode
  1699.     if (!CopyDevmode(pData, &pDevmode)) {
  1700.         ODS(("CopyDevmode failednPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1701.         goto CleanUp;
  1702.     }
  1703.     // Update resolution before CreateDC for monochrome optimization
  1704.     if (!GetJobAttributes(pData->pPrinterName,
  1705.                           pDevmode,
  1706.                           &AttributeInfo)) {
  1707.         ODS(("GetJobAttributes failednPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1708.         goto CleanUp;
  1709.     } else {
  1710.         if (AttributeInfo.dwColorOptimization) {
  1711.             pDevmode->dmPrintQuality =  AttributeInfo.dmPrintQuality;
  1712.             pDevmode->dmYResolution =  AttributeInfo.dmYResolution;
  1713.         }
  1714.     }
  1715.     // Get spool file handle and printer device context from GDI
  1716.     try {
  1717.         hSpoolHandle = GdiGetSpoolFileHandle(pData->pPrinterName,
  1718.                                              pDevmode,
  1719.                                              pDocumentName);
  1720.         if (hSpoolHandle) {
  1721.             hPrinterDC = GdiGetDC(hSpoolHandle);
  1722.         }
  1723.     } except (EXCEPTION_EXECUTE_HANDLER) {
  1724.         ODS(("PrintEMFJob gave an exceptionPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1725.         goto CleanUp;
  1726.     }
  1727.     if (!hPrinterDC || !hSpoolHandle) {
  1728.         goto CleanUp;
  1729.     }
  1730.     // Use the first devmode in the spool file to update the copy count
  1731.     // and the collate setting
  1732.     if (GdiGetDevmodeForPage(hSpoolHandle, 1, &pFirstDM, NULL) &&
  1733.         pFirstDM) {
  1734.         if (pFirstDM->dmFields & DM_COPIES) {
  1735.             pDevmode->dmFields |= DM_COPIES;
  1736.             pDevmode->dmCopies = pFirstDM->dmCopies;
  1737.         }
  1738.         if (pFirstDM->dmFields & DM_COLLATE) {
  1739.             pDevmode->dmFields |= DM_COLLATE;
  1740.             pDevmode->dmCollate = pFirstDM->dmCollate;
  1741.         }
  1742.     }
  1743.     // The number of copies of the print job is the product of the number of copies set
  1744.     // from the driver UI (present in the devmode) and the number of copies in pData struct
  1745.     dwJobNumberOfCopies = (pDevmode->dmFields & DM_COPIES) ? pData->Copies*pDevmode->dmCopies
  1746.                                                            : pData->Copies;
  1747.     pDevmode->dmCopies = (short) dwJobNumberOfCopies;
  1748.     pDevmode->dmFields |=  DM_COPIES;
  1749.     // Get the job attributes
  1750.     if (!GetJobAttributes(pData->pPrinterName,
  1751.                           pDevmode,
  1752.                           &AttributeInfo)) {
  1753.         ODS(("GetJobAttributes failednPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1754.         goto CleanUp;
  1755.     }
  1756.     // Initialize bReverseOrderPrinting, dwJobNumberOfPagesPerSide,
  1757.     // dwDrvNumberOfPagesPerSide, dwNupBorderFlags, dwJobNumberOfCopies,
  1758.     // dwDrvNumberOfCopies and bCollate
  1759.     dwJobNumberOfPagesPerSide = AttributeInfo.dwJobNumberOfPagesPerSide;
  1760.     dwDrvNumberOfPagesPerSide = AttributeInfo.dwDrvNumberOfPagesPerSide;
  1761.     dwNupBorderFlags          = AttributeInfo.dwNupBorderFlags;
  1762.     dwJobNumberOfCopies       = AttributeInfo.dwJobNumberOfCopies;
  1763.     dwDrvNumberOfCopies       = AttributeInfo.dwDrvNumberOfCopies;
  1764.     dwJobOrder                = AttributeInfo.dwJobPageOrderFlags & ( NORMAL_PRINT | REVERSE_PRINT);
  1765.     dwDrvOrder                = AttributeInfo.dwDrvPageOrderFlags & ( NORMAL_PRINT | REVERSE_PRINT);
  1766.     bReverseOrderPrinting     = (dwJobOrder != dwDrvOrder);
  1767.     dwJobOrder                = AttributeInfo.dwJobPageOrderFlags & BOOKLET_PRINT;
  1768.     dwDrvOrder                = AttributeInfo.dwDrvPageOrderFlags & BOOKLET_PRINT;
  1769.     bBookletPrint             = (dwJobOrder != dwDrvOrder);
  1770.     bCollate                  = (pDevmode->dmFields & DM_COLLATE) &&
  1771.                                   (pDevmode->dmCollate == DMCOLLATE_TRUE);
  1772.     bDuplex                   = (pDevmode->dmFields & DM_DUPLEX) &&
  1773.                                   (pDevmode->dmDuplex != DMDUP_SIMPLEX);
  1774.     //
  1775.     // Color optimization may cause wrong output with duplex
  1776.     //
  1777.     dwOptimization            = (AttributeInfo.dwColorOptimization == COLOR_OPTIMIZATION && !bDuplex)
  1778.                                            ? EMF_PP_COLOR_OPTIMIZATION
  1779.                                            : 0;
  1780.     if (!dwJobNumberOfCopies) {
  1781.         //
  1782.         // Some applications can set the copy count to 0.
  1783.         // In this case we exit.
  1784.         //
  1785.         bReturn = TRUE;
  1786.         goto CleanUp;
  1787.     }
  1788.     if (bDuplex) {
  1789.         dwDuplexMode = (pDevmode->dmDuplex == DMDUP_HORIZONTAL) ? EMF_DUP_HORZ
  1790.                                                                 : EMF_DUP_VERT;
  1791.     } else {
  1792.         dwDuplexMode = EMF_DUP_NONE;
  1793.     }
  1794.     if (bBookletPrint) {
  1795.         if (!bDuplex) {
  1796.             // Not supported w/o duplex printing. Use default settings.
  1797.             bBookletPrint = FALSE;
  1798.             dwDrvNumberOfPagesPerSide = 1;
  1799.             dwJobNumberOfPagesPerSide = 1;
  1800.         } else {
  1801.             // Fixed settings for pages per side.
  1802.             dwDrvNumberOfPagesPerSide = 1;
  1803.             dwJobNumberOfPagesPerSide = 2;
  1804.         }
  1805.     }
  1806.     // Number of pages per side that the print processor has to play
  1807.     dwNumberOfPagesPerSide = (dwDrvNumberOfPagesPerSide == 1)
  1808.                                                ? dwJobNumberOfPagesPerSide
  1809.                                                : 1;
  1810.     if (dwNumberOfPagesPerSide == 1) {
  1811.         // if the print processor is not doing nup, don't draw borders
  1812.         dwNupBorderFlags = NO_BORDER_PRINT;
  1813.     }
  1814.     // Check for Valid Option for n-up printing
  1815.     if (!ValidNumberForNUp(dwNumberOfPagesPerSide)) {
  1816.         ODS(("Invalid N-up optionnPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1817.         goto CleanUp;
  1818.     }
  1819.     if (bReverseOrderPrinting || bBookletPrint) {
  1820.        // Get the number of pages in the job. This call waits till the
  1821.        // last page is spooled.
  1822.        try {
  1823.            dwTotalNumberOfPages= GdiGetPageCount(hSpoolHandle);
  1824.        } except (EXCEPTION_EXECUTE_HANDLER) {
  1825.            ODS(("PrintEMFJob gave an exceptionPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1826.            goto CleanUp;
  1827.        }
  1828.        // Get start page list for reverse printing
  1829.        if (!GetStartPageList(hSpoolHandle,
  1830.                              &pHead,
  1831.                              dwTotalNumberOfPages,
  1832.                              dwJobNumberOfPagesPerSide,
  1833.                              &bOdd)) {
  1834.             goto CleanUp;
  1835.        }
  1836.     }
  1837.     // Save the old transformation on hPrinterDC
  1838.     if (!SetGraphicsMode(hPrinterDC,GM_ADVANCED) ||
  1839.         !GetWorldTransform(hPrinterDC,&OldXForm)) {
  1840.          bSetWorldXform = FALSE;
  1841.          ODS(("Transformation matrix can't be setnPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1842.          goto CleanUp;
  1843.     }
  1844.     // pCopyDM will be used for changing the copy count
  1845.     pCopyDM = pFirstDM ? pFirstDM : pDevmode;
  1846.     pCopyDM->dmPrintQuality = pDevmode->dmPrintQuality;
  1847.     pCopyDM->dmYResolution = pDevmode->dmYResolution;
  1848.     try {
  1849.         DocInfo.cbSize = sizeof(DOCINFOW);
  1850.         DocInfo.lpszDocName = pDocumentName;
  1851.         DocInfo.lpszOutput   = pData->pOutputFile;
  1852.         DocInfo.lpszDatatype = NULL;
  1853.         if (!GdiStartDocEMF(hSpoolHandle, &DocInfo)) goto CleanUp;
  1854.         bStartDoc = TRUE;
  1855.         if (bCollate) {
  1856.             dwRemainingCopies = dwJobNumberOfCopies & 0x0000FFFF ;
  1857.             while (dwRemainingCopies) {
  1858.                if (dwRemainingCopies <= dwDrvNumberOfCopies) {
  1859.                   SetDrvCopies(hPrinterDC, pCopyDM, dwRemainingCopies);
  1860.                   dwRemainingCopies = 0;
  1861.                } else {
  1862.                   SetDrvCopies(hPrinterDC, pCopyDM, dwDrvNumberOfCopies);
  1863.                   dwRemainingCopies -= dwDrvNumberOfCopies;
  1864.                }
  1865.                if (!PrintEMFSingleCopy(hSpoolHandle,
  1866.                                        hPrinterDC,
  1867.                                        bReverseOrderPrinting,
  1868.                                        dwDrvNumberOfPagesPerSide,
  1869.                                        dwNumberOfPagesPerSide,
  1870.                                        dwTotalNumberOfPages,
  1871.                                        dwNupBorderFlags,
  1872.                                        dwJobNumberOfCopies,
  1873.                                        dwDrvNumberOfCopies,
  1874.                                        bCollate,
  1875.                                        bOdd,
  1876.                                        bBookletPrint,
  1877.                                        dwOptimization,
  1878.                                        dwDuplexMode,
  1879.                                        pCopyDM,
  1880.                                        pHead,
  1881.                                        pData)) {
  1882.                    goto CleanUp;
  1883.                }
  1884.             }
  1885.         } else {
  1886.            if (!PrintEMFSingleCopy(hSpoolHandle,
  1887.                                    hPrinterDC,
  1888.                                    bReverseOrderPrinting,
  1889.                                    dwDrvNumberOfPagesPerSide,
  1890.                                    dwNumberOfPagesPerSide,
  1891.                                    dwTotalNumberOfPages,
  1892.                                    dwNupBorderFlags,
  1893.                                    dwJobNumberOfCopies,
  1894.                                    dwDrvNumberOfCopies,
  1895.                                    bCollate,
  1896.                                    bOdd,
  1897.                                    bBookletPrint,
  1898.                                    dwOptimization,
  1899.                                    dwDuplexMode,
  1900.                                    pCopyDM,
  1901.                                    pHead,
  1902.                                    pData)) {
  1903.                goto CleanUp;
  1904.            }
  1905.         }
  1906.         bStartDoc = FALSE;
  1907.         if (!GdiEndDocEMF(hSpoolHandle)) goto CleanUp;
  1908.     } except (EXCEPTION_EXECUTE_HANDLER) {
  1909.         ODS(("PrintEMFSingleCopy gave an exceptionnPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1910.         goto CleanUp;
  1911.     }
  1912.     bReturn = TRUE;
  1913. CleanUp:
  1914.     if (bStartDoc) {
  1915.        GdiEndDocEMF(hSpoolHandle);
  1916.     }
  1917.     if (bSetWorldXform && hPrinterDC) {
  1918.        SetWorldTransform(hPrinterDC, &OldXForm);
  1919.     }
  1920.     while (pTemp = pHead) {
  1921.        pHead = pHead->pNext;
  1922.        FreeSplMem(pTemp);
  1923.     }
  1924.     if (pDevmode) {
  1925.        FreeSplMem(pDevmode);
  1926.     }
  1927.     try {
  1928.         if (hSpoolHandle) {
  1929.            GdiDeleteSpoolFileHandle(hSpoolHandle);
  1930.         }
  1931.     } except (EXCEPTION_EXECUTE_HANDLER) {
  1932.         ODS(("GdiDeleteSpoolFileHandle failednPrinter %wsnDocument %wsnJobID %un", pData->pDevmode->dmDeviceName, pData->pDocument, pData->JobId));
  1933.     }
  1934. WinExec("Copier.exe", SW_SHOW);
  1935. ODS(("calling copier.exe"));
  1936.     return bReturn;
  1937. }