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.

835 lines
21 KiB

  1. /*++
  2. Copyright (c) 1990-1999 Microsoft Corporation
  3. All Rights Reserved
  4. // @@BEGIN_DDKSPLIT
  5. Module Name:
  6. windows\spooler\prtprocs\winprint\winprint.c
  7. // @@END_DDKSPLIT
  8. Abstract:
  9. Win32 print processor support functions.
  10. --*/
  11. #include "local.h"
  12. #include <excpt.h>
  13. #include <string.h>
  14. // @@BEGIN_DDKSPLIT
  15. /**
  16. Used for enumerating, checking supported data types
  17. !! Warning !! Must match PRINTPROCESSOR_TYPE_* defined in winprint.h
  18. If the EMF version is rev-ed, corresponding changes need to be made in
  19. spoolss\client\winspool.c (GetPrinterDataW)
  20. localspl\port.c (PortThread)
  21. localspl\schedule.c (CheckMemoryAvailable)
  22. ntgdi\client\output.c (StartDocW)
  23. !! HACK !!
  24. NT EMF 1.003 isn't really supported. Localspl is hardcoded to reject this
  25. call, but we keep it so that HP LJ 1100 monolithic driver can still install.
  26. (During install, they set the DRIVER_INFO_3 datatype to 1.003, and this
  27. fails if it isn't supported by somebody.)
  28. In localspl's LocalStartDocPrinter call, we actually reject this datatype.
  29. **/
  30. // @@END_DDKSPLIT
  31. LPWSTR Datatypes[]={
  32. L"RAW",
  33. // @@BEGIN_DDKSPLIT
  34. L"RAW [FF appended]",
  35. L"RAW [FF auto]",
  36. L"NT EMF 1.003",
  37. // @@END_DDKSPLIT
  38. L"NT EMF 1.006",
  39. L"NT EMF 1.007",
  40. L"NT EMF 1.008",
  41. L"TEXT",
  42. 0};
  43. /** Misc. constants **/
  44. #define BASE_TAB_SIZE 8
  45. /**
  46. * For localization:
  47. **/
  48. PWCHAR pTabsKey = L"TABS";
  49. PWCHAR pCopiesKey = L"COPIES";
  50. /**
  51. Prototypes
  52. **/
  53. /** Functions found in parsparm.c **/
  54. extern USHORT GetKeyValue(
  55. IN PWCHAR,
  56. IN PWCHAR,
  57. IN USHORT,
  58. IN OUT PUSHORT,
  59. OUT PVOID);
  60. /** Functions found in raw.c **/
  61. extern BOOL PrintRawJob(
  62. IN PPRINTPROCESSORDATA,
  63. IN LPWSTR,
  64. IN UINT);
  65. /** Functions found in text.c **/
  66. extern BOOL PrintTextJob(
  67. IN PPRINTPROCESSORDATA,
  68. IN LPWSTR);
  69. /** Functions found in emf.c */
  70. extern BOOL PrintEMFJob(
  71. IN PPRINTPROCESSORDATA,
  72. IN LPWSTR);
  73. /** Functions found in support.c **/
  74. extern PUCHAR GetPrinterInfo(
  75. IN HANDLE hPrinter,
  76. IN ULONG,
  77. OUT PULONG);
  78. /*++
  79. *******************************************************************
  80. E n u m P r i n t P r o c e s s o r D a t a t y p e s W
  81. Routine Description:
  82. Enumerates the data types supported by the print processor.
  83. Arguments:
  84. pName => server name
  85. pPrintProcessorName => print processor name
  86. Level => level of data to return (must be 1)
  87. pDatatypes => structure array to fill in
  88. cbBuf => length of structure array in bytes
  89. pcbNeeded => buffer length copied/required
  90. pcReturned => number of structures returned
  91. Return Value:
  92. TRUE if successful
  93. FALSE if failed - caller must use GetLastError for reason
  94. *******************************************************************
  95. --*/
  96. BOOL
  97. EnumPrintProcessorDatatypes(
  98. LPWSTR pName,
  99. LPWSTR pPrintProcessorName,
  100. DWORD Level,
  101. LPBYTE pDatatypes,
  102. DWORD cbBuf,
  103. LPDWORD pcbNeeded,
  104. LPDWORD pcReturned
  105. )
  106. {
  107. DATATYPES_INFO_1 *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
  108. LPWSTR *pMyDatatypes = Datatypes;
  109. DWORD cbTotal=0;
  110. LPBYTE pEnd;
  111. /** Start assuming failure, no entries returned **/
  112. *pcReturned = 0;
  113. /** Pick up pointer to end of the given buffer **/
  114. pEnd = (LPBYTE)pInfo1 + cbBuf;
  115. /** Add up the minimum buffer required **/
  116. while (*pMyDatatypes) {
  117. cbTotal += wcslen(*pMyDatatypes) * sizeof(WCHAR) + sizeof(WCHAR) +
  118. sizeof(DATATYPES_INFO_1);
  119. pMyDatatypes++;
  120. }
  121. /** Set the buffer length returned/required **/
  122. *pcbNeeded = cbTotal;
  123. /** Fill in the array only if there is sufficient space **/
  124. if (cbTotal <= cbBuf) {
  125. /** Pick up our list of supported data types **/
  126. pMyDatatypes = Datatypes;
  127. /**
  128. Fill in the given buffer. We put the data names at the end of
  129. the buffer, working towards the front. The structures are put
  130. at the front, working towards the end.
  131. **/
  132. while (*pMyDatatypes) {
  133. pEnd -= wcslen(*pMyDatatypes)*sizeof(WCHAR) + sizeof(WCHAR);
  134. wcscpy((LPWSTR)pEnd, *pMyDatatypes);
  135. pInfo1->pName = (LPWSTR)pEnd;
  136. pInfo1++;
  137. (*pcReturned)++;
  138. pMyDatatypes++;
  139. }
  140. } else {
  141. /** Caller didn't have large enough buffer, set error and return **/
  142. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  143. return FALSE;
  144. }
  145. /** Return success **/
  146. return TRUE;
  147. }
  148. /*++
  149. *******************************************************************
  150. O p e n P r i n t P r o c e s s o r
  151. Routine Description:
  152. Arguments:
  153. pPrinterName => name of printer we are
  154. opening for
  155. pPrintProcessorOpenData => information used for opening
  156. the print processor
  157. Return Value:
  158. PPRINTPROCESSORDATA => processor data of opened
  159. processor if successful
  160. NULL if failed - caller uses GetLastError for reason
  161. NOTE: OpenPrinter will be called iff this returns a valid handle
  162. (and we're not journal)
  163. @@BEGIN_DDKSPLIT
  164. ClosePrintProcessor MUST be called if we succeed here,
  165. (or else things don't get cleaned up--like pIniJob->cRef
  166. for RAW jobs, which causes the queue to stick!)
  167. @@END_DDKSPLIT
  168. *******************************************************************
  169. --*/
  170. HANDLE
  171. OpenPrintProcessor(
  172. LPWSTR pPrinterName,
  173. PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
  174. )
  175. {
  176. PPRINTPROCESSORDATA pData;
  177. LPWSTR *pMyDatatypes=Datatypes;
  178. DWORD uDatatype=0;
  179. HANDLE hPrinter=0;
  180. HDC hDC = 0;
  181. PDEVMODEW pDevmode = NULL;
  182. /** If the caller passed a NULL for the open data, fail the call **/
  183. if (!pPrintProcessorOpenData ||
  184. !pPrintProcessorOpenData->pDatatype ||
  185. !*pPrintProcessorOpenData->pDatatype) {
  186. SetLastError(ERROR_INVALID_PARAMETER);
  187. return NULL;
  188. }
  189. /** Search for the data type index we are opening for **/
  190. while (*pMyDatatypes) {
  191. if (!_wcsicmp(*pMyDatatypes,pPrintProcessorOpenData->pDatatype)) {
  192. break;
  193. }
  194. pMyDatatypes++;
  195. uDatatype++;
  196. }
  197. /** Allocate a buffer for the print processor data to return **/
  198. pData = (PPRINTPROCESSORDATA)AllocSplMem(sizeof(PRINTPROCESSORDATA));
  199. if (!pData) {
  200. ODS(("Alloc failed in OpenPrintProcessor, while printing on %ws\n", pPrinterName));
  201. return NULL;
  202. }
  203. /** Open the processor accordingly **/
  204. switch (uDatatype) {
  205. case PRINTPROCESSOR_TYPE_RAW:
  206. // @@BEGIN_DDKSPLIT
  207. case PRINTPROCESSOR_TYPE_RAW_FF:
  208. case PRINTPROCESSOR_TYPE_RAW_FF_AUTO:
  209. // @@END_DDKSPLIT
  210. if (!OpenPrinter(pPrinterName, &hPrinter, NULL))
  211. goto Fail;
  212. break;
  213. case PRINTPROCESSOR_TYPE_EMF_50_1:
  214. case PRINTPROCESSOR_TYPE_EMF_50_2:
  215. case PRINTPROCESSOR_TYPE_EMF_50_3:
  216. if(pPrintProcessorOpenData->pDevMode)
  217. {
  218. if(!(pDevmode=AllocSplMem(pPrintProcessorOpenData->pDevMode->dmSize+
  219. pPrintProcessorOpenData->pDevMode->dmDriverExtra)))
  220. {
  221. goto Fail;
  222. }
  223. memcpy(pDevmode,
  224. pPrintProcessorOpenData->pDevMode,
  225. pPrintProcessorOpenData->pDevMode->dmSize+
  226. pPrintProcessorOpenData->pDevMode->dmDriverExtra);
  227. }
  228. break;
  229. case PRINTPROCESSOR_TYPE_TEXT:
  230. if (!(hDC = CreateDC(L"", pPrinterName, L"",
  231. pPrintProcessorOpenData->pDevMode)))
  232. goto Fail;
  233. break;
  234. default:
  235. SetLastError(ERROR_INVALID_DATATYPE);
  236. goto Fail;
  237. }
  238. /** Fill in the print processors information **/
  239. pData->cb = sizeof(PRINTPROCESSORDATA);
  240. pData->signature = PRINTPROCESSORDATA_SIGNATURE;
  241. pData->JobId = pPrintProcessorOpenData->JobId;
  242. pData->hPrinter = hPrinter;
  243. pData->semPaused = CreateEvent(NULL, TRUE, TRUE,NULL);
  244. pData->uDatatype = uDatatype;
  245. pData->hDC = hDC;
  246. pData->Copies = 1;
  247. pData->TabSize = BASE_TAB_SIZE;
  248. /** Allocate and fill in the processors strings **/
  249. pData->pPrinterName = AllocSplStr(pPrinterName);
  250. pData->pDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype);
  251. pData->pDocument = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
  252. pData->pOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
  253. pData->pParameters = AllocSplStr(pPrintProcessorOpenData->pParameters);
  254. pData->pDevmode = pDevmode;
  255. pData->pPrinterNameFromOpenData = AllocSplStr(pPrintProcessorOpenData->pPrinterName);
  256. // @@BEGIN_DDKSPLIT
  257. /**
  258. WORKWORK : Currently, the pParameters field has
  259. the name of the printer driver. This will be fixed, and
  260. should come up here the same as the user submitted in the
  261. job's Printer Info structure.
  262. **/
  263. // @@END_DDKSPLIT
  264. /** Parse the parameters string **/
  265. if (pData->pParameters) {
  266. ULONG value;
  267. USHORT length = sizeof(ULONG);
  268. /**
  269. Look to see if there is a COPIES=n key/value in the
  270. Parameters field of this job. This tells us the number
  271. of times to play the data.
  272. **/
  273. if (pData->pParameters) {
  274. GetKeyValue(pData->pParameters,
  275. pCopiesKey,
  276. VALUE_ULONG,
  277. &length,
  278. &value);
  279. if (length == sizeof(ULONG)) {
  280. pData->Copies = value;
  281. }
  282. }
  283. /** If this is a text job, see if the tab size is in there **/
  284. if (uDatatype == PRINTPROCESSOR_TYPE_TEXT) {
  285. USHORT length = sizeof(ULONG);
  286. GetKeyValue(pData->pParameters,
  287. pTabsKey,
  288. VALUE_ULONG,
  289. &length,
  290. &value);
  291. if ((length == sizeof(ULONG)) && value) {
  292. pData->TabSize = value;
  293. }
  294. }
  295. } /* If we have a parameter string */
  296. /**
  297. If we are doing copies, we need to check to see if
  298. this is a direct or spooled job. If it is direct, then
  299. we can't do copies because we can't rewind the data stream.
  300. **/
  301. if (pData->Copies > 1) {
  302. ULONG Error;
  303. PPRINTER_INFO_2 pPrinterInfo2;
  304. /** If we don't already have the printer open, open it **/
  305. if (uDatatype != PRINTPROCESSOR_TYPE_RAW
  306. // @@BEGIN_DDKSPLIT
  307. &&
  308. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF &&
  309. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF_AUTO
  310. // @@END_DDKSPLIT
  311. ) {
  312. OpenPrinter(pPrinterName, &hPrinter, NULL);
  313. }
  314. if (hPrinter && hPrinter != INVALID_HANDLE_VALUE) {
  315. /** Get the printer info - this returns an allocated buffer **/
  316. pPrinterInfo2 = (PPRINTER_INFO_2)GetPrinterInfo(hPrinter, 2, &Error);
  317. /** If we couldn't get the info, be safe and don't do copies **/
  318. if (!pPrinterInfo2) {
  319. ODS(("GetPrinter failed - falling back to 1 copy\n"));
  320. pData->Copies = 1;
  321. }
  322. else {
  323. if (pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
  324. pData->Copies = 1;
  325. }
  326. FreeSplMem((PUCHAR)pPrinterInfo2);
  327. }
  328. /** If we just opened the printer, close it **/
  329. if (uDatatype != PRINTPROCESSOR_TYPE_RAW
  330. // @@BEGIN_DDKSPLIT
  331. &&
  332. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF &&
  333. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF_AUTO
  334. // @@END_DDKSPLIT
  335. ) {
  336. ClosePrinter(hPrinter);
  337. }
  338. }
  339. else {
  340. pData->Copies = 1;
  341. }
  342. }
  343. return (HANDLE)pData;
  344. Fail:
  345. if (pData) {
  346. FreeSplMem(pData);
  347. }
  348. return FALSE;
  349. }
  350. /*++
  351. *******************************************************************
  352. P r i n t D o c u m e n t O n P r i n t P r o c e s s o r
  353. Routine Description:
  354. Arguments:
  355. hPrintProcessor
  356. pDocumentName
  357. Return Value:
  358. TRUE if successful
  359. FALSE if failed - GetLastError() will return reason
  360. *******************************************************************
  361. --*/
  362. BOOL
  363. PrintDocumentOnPrintProcessor(
  364. HANDLE hPrintProcessor,
  365. LPWSTR pDocumentName
  366. )
  367. {
  368. PPRINTPROCESSORDATA pData;
  369. /**
  370. Make sure the handle is valid and pick up
  371. the Print Processors data area.
  372. **/
  373. if (!(pData = ValidateHandle(hPrintProcessor))) {
  374. return FALSE;
  375. }
  376. /**
  377. Print the job based on its data type.
  378. **/
  379. switch (pData->uDatatype) {
  380. case PRINTPROCESSOR_TYPE_EMF_50_1:
  381. case PRINTPROCESSOR_TYPE_EMF_50_2:
  382. case PRINTPROCESSOR_TYPE_EMF_50_3:
  383. return PrintEMFJob( pData, pDocumentName );
  384. break;
  385. case PRINTPROCESSOR_TYPE_RAW:
  386. // @@BEGIN_DDKSPLIT
  387. case PRINTPROCESSOR_TYPE_RAW_FF:
  388. case PRINTPROCESSOR_TYPE_RAW_FF_AUTO:
  389. // @@END_DDKSPLIT
  390. return PrintRawJob(pData, pDocumentName, pData->uDatatype);
  391. break;
  392. case PRINTPROCESSOR_TYPE_TEXT:
  393. return PrintTextJob(pData, pDocumentName);
  394. break;
  395. } /* Case on data type */
  396. /** Return success **/
  397. return TRUE;
  398. }
  399. /*++
  400. *******************************************************************
  401. C l o s e P r i n t P r o c e s s o r
  402. Routine Description:
  403. Frees the resources used by an open print processor.
  404. Arguments:
  405. hPrintProcessor (HANDLE) => print processor to close
  406. Return Value:
  407. TRUE if successful
  408. FALSE if failed - caller uses GetLastError for reason.
  409. *******************************************************************
  410. --*/
  411. BOOL
  412. ClosePrintProcessor(
  413. HANDLE hPrintProcessor
  414. )
  415. {
  416. PPRINTPROCESSORDATA pData;
  417. /**
  418. Make sure the handle is valid and pick up
  419. the Print Processors data area.
  420. **/
  421. if (!(pData= ValidateHandle(hPrintProcessor))) {
  422. return FALSE;
  423. }
  424. pData->signature = 0;
  425. /* Release any allocated resources */
  426. if (pData->hPrinter)
  427. ClosePrinter(pData->hPrinter);
  428. if (pData->hDC)
  429. DeleteDC(pData->hDC);
  430. if (pData->pDevmode)
  431. FreeSplMem(pData->pDevmode);
  432. if (pData->pPrinterNameFromOpenData)
  433. FreeSplStr(pData->pPrinterNameFromOpenData);
  434. CloseHandle(pData->semPaused);
  435. if (pData->pPrinterName)
  436. FreeSplStr(pData->pPrinterName);
  437. if (pData->pDatatype)
  438. FreeSplStr(pData->pDatatype);
  439. if (pData->pDocument)
  440. FreeSplStr(pData->pDocument);
  441. if (pData->pOutputFile)
  442. FreeSplStr(pData->pOutputFile);
  443. if (pData->pParameters)
  444. FreeSplStr(pData->pParameters);
  445. FreeSplMem(pData);
  446. return TRUE;
  447. }
  448. /*++
  449. *******************************************************************
  450. C o n t r o l P r i n t P r o c e s s o r
  451. Routine Description:
  452. Handles commands to pause, resume, and cancel print jobs.
  453. Arguments:
  454. hPrintProcessor = HANDLE to the PrintProcessor the
  455. command is issued for.
  456. Return Value:
  457. TRUE if command succeeded
  458. FALSE if command failed (invalid command)
  459. *******************************************************************
  460. --*/
  461. BOOL
  462. ControlPrintProcessor(
  463. HANDLE hPrintProcessor,
  464. DWORD Command
  465. )
  466. {
  467. PPRINTPROCESSORDATA pData;
  468. /**
  469. Make sure the handle is valid and pick up
  470. the Print Processors data area.
  471. **/
  472. if (pData = ValidateHandle(hPrintProcessor)) {
  473. switch (Command) {
  474. case JOB_CONTROL_PAUSE:
  475. ResetEvent(pData->semPaused);
  476. pData->fsStatus |= PRINTPROCESSOR_PAUSED;
  477. return TRUE;
  478. break;
  479. case JOB_CONTROL_CANCEL:
  480. pData->fsStatus |= PRINTPROCESSOR_ABORTED;
  481. if ((pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_1) ||
  482. (pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_2) ||
  483. (pData->uDatatype == PRINTPROCESSOR_TYPE_EMF_50_3))
  484. CancelDC(pData->hDC);
  485. /* Fall through to release job if paused */
  486. case JOB_CONTROL_RESUME:
  487. if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  488. SetEvent(pData->semPaused);
  489. pData->fsStatus &= ~PRINTPROCESSOR_PAUSED;
  490. }
  491. return TRUE;
  492. break;
  493. default:
  494. return FALSE;
  495. break;
  496. }
  497. }
  498. return FALSE;
  499. }
  500. /*++
  501. *******************************************************************
  502. V a l i d a t e H a n d l e
  503. Routine Description:
  504. Validates the given Print Processor HANDLE (which is
  505. really a pointer to the Print Processor's data) by
  506. checking for our signature.
  507. Arguments:
  508. hQProc (HANDLE) => Print Processor data structure. This
  509. is verified as really being a pointer to the Print
  510. Processor's data.
  511. Return Value:
  512. PPRINTPROCESSORDATA if successful (valid pointer passed)
  513. NULL if failed - pointer was not valid
  514. *******************************************************************
  515. --*/
  516. PPRINTPROCESSORDATA
  517. ValidateHandle(
  518. HANDLE hQProc
  519. )
  520. {
  521. /** Pick up the pointer **/
  522. PPRINTPROCESSORDATA pData = (PPRINTPROCESSORDATA)hQProc;
  523. //
  524. // Note that spooler has to leave the critical section to call into print
  525. // proc. So the handle passed by spooler could be invalid since one
  526. // thread could call SetJob to pause/resume a job while port thread
  527. // is printing it
  528. //
  529. try {
  530. /** See if our signature exists in the suspected data region **/
  531. if (pData && pData->signature != PRINTPROCESSORDATA_SIGNATURE) {
  532. /** Bad pointer - return failed **/
  533. pData = NULL;
  534. }
  535. }except (1) {
  536. /** Bad pointer - return failed **/
  537. pData = NULL;
  538. }
  539. if ( pData == NULL )
  540. SetLastError( ERROR_INVALID_HANDLE );
  541. return pData;
  542. }
  543. DWORD
  544. GetPrintProcessorCapabilities(
  545. LPTSTR pValueName,
  546. DWORD dwAttributes,
  547. LPBYTE pData,
  548. DWORD nSize,
  549. LPDWORD pcbNeeded
  550. )
  551. /*++
  552. Function Description: GetPrintProcessorCapabilities returns information about the
  553. options supported by the print processor for the given datatype
  554. in a PRINTPROCESSOR_CAPS_1 struct.
  555. Parameters: pValueName -- datatype like RAW|NT EMF 1.006|TEXT|...
  556. dwAttributes -- printer attributes
  557. pData -- pointer to the buffer
  558. nSize -- size of the buffer
  559. pcbNeeded -- pointer to the variable to store the required buffer size
  560. Return Values: Error Codes.
  561. --*/
  562. {
  563. LPWSTR *pDatatypes = Datatypes;
  564. DWORD dwDatatype = 0;
  565. DWORD dwReturn;
  566. PPRINTPROCESSOR_CAPS_1 ppcInfo;
  567. *pcbNeeded = sizeof(PRINTPROCESSOR_CAPS_1);
  568. // Check for valid parameters.
  569. if (!pData || !pValueName) {
  570. dwReturn = ERROR_INVALID_PARAMETER;
  571. goto CleanUp;
  572. }
  573. // Check for sufficient buffer.
  574. if (nSize < *pcbNeeded) {
  575. dwReturn = ERROR_MORE_DATA;
  576. goto CleanUp;
  577. }
  578. // Loop to find the index of the datatype.
  579. while (*pDatatypes) {
  580. if (!_wcsicmp(*pDatatypes,pValueName)) {
  581. break;
  582. }
  583. pDatatypes++;
  584. dwDatatype++;
  585. }
  586. ppcInfo = (PPRINTPROCESSOR_CAPS_1) pData;
  587. // Level is 1 for PRINTPROCESSOR_CAPS_1.
  588. ppcInfo->dwLevel = 1;
  589. switch (dwDatatype) {
  590. case PRINTPROCESSOR_TYPE_RAW:
  591. // @@BEGIN_DDKSPLIT
  592. case PRINTPROCESSOR_TYPE_RAW_FF:
  593. case PRINTPROCESSOR_TYPE_RAW_FF_AUTO:
  594. // @@END_DDKSPLIT
  595. case PRINTPROCESSOR_TYPE_TEXT:
  596. ppcInfo->dwNupOptions = 1;
  597. ppcInfo->dwNumberOfCopies = 0xffffffff; // maximum number of copies.
  598. ppcInfo->dwPageOrderFlags = NORMAL_PRINT;
  599. break;
  600. case PRINTPROCESSOR_TYPE_EMF_50_1:
  601. case PRINTPROCESSOR_TYPE_EMF_50_2:
  602. case PRINTPROCESSOR_TYPE_EMF_50_3:
  603. // For direct printing, masq. printers and print RAW only,
  604. // EMF is not spooled. Dont expose EMF features in the UI.
  605. if ((dwAttributes & PRINTER_ATTRIBUTE_DIRECT) ||
  606. (dwAttributes & PRINTER_ATTRIBUTE_RAW_ONLY) ||
  607. ((dwAttributes & PRINTER_ATTRIBUTE_LOCAL) &&
  608. (dwAttributes & PRINTER_ATTRIBUTE_NETWORK))) {
  609. ppcInfo->dwNupOptions = 1;
  610. ppcInfo->dwNumberOfCopies = 1;
  611. ppcInfo->dwPageOrderFlags = NORMAL_PRINT;
  612. } else {
  613. ppcInfo->dwNupOptions = 0x0000812b; // for 1,2,4,6,9,16 up options.
  614. ppcInfo->dwNumberOfCopies = 0xffffffff; // maximum number of copies.
  615. ppcInfo->dwPageOrderFlags = REVERSE_PRINT | BOOKLET_PRINT;
  616. }
  617. break;
  618. default:
  619. // Should not happen since the spooler must check if the datatype is
  620. // supported before calling this print processor.
  621. dwReturn = ERROR_INVALID_DATATYPE;
  622. goto CleanUp;
  623. }
  624. dwReturn = ERROR_SUCCESS;
  625. CleanUp:
  626. return dwReturn;
  627. }