Leaked source code of windows server 2003
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.

2773 lines
97 KiB

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