Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2542 lines
88 KiB

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