Windows NT 4.0 source code leak
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.

734 lines
18 KiB

4 years ago
  1. /*++
  2. Module Name:
  3. windows\spooler\prtprocs\winprint\winprint.c
  4. Abstract:
  5. Win32 print processor support functions.
  6. Author:
  7. Dave Snip (davesn) - (I guess)
  8. Revision History:
  9. Tommy Evans (vtommye) 10-15-1993 - commented code and added
  10. support for TEXT data and
  11. processor generated copies.
  12. --*/
  13. #include <windows.h>
  14. #include <winspool.h>
  15. #include <winsplp.h>
  16. #include "winprint.h"
  17. #include <excpt.h>
  18. #include <string.h>
  19. /**
  20. Used for enumerating, checking supported data types
  21. !! Warning !! Must match PRINTPROCESSOR_TYPE_* defined in winprint.h
  22. **/
  23. LPWSTR Datatypes[]={
  24. L"RAW",
  25. L"RAW [FF appended]",
  26. L"RAW [FF auto]",
  27. L"NT EMF 1.003",
  28. L"TEXT",
  29. 0};
  30. /** Misc. constants **/
  31. #define BASE_TAB_SIZE 8
  32. /**
  33. * For localization:
  34. **/
  35. PWCHAR pTabsKey = L"TABS";
  36. PWCHAR pCopiesKey = L"COPIES";
  37. /**
  38. Prototypes
  39. **/
  40. /** Functions found in parsparm.c **/
  41. extern USHORT GetKeyValue(
  42. IN PWCHAR,
  43. IN PWCHAR,
  44. IN USHORT,
  45. IN OUT PUSHORT,
  46. OUT PVOID);
  47. /** Functions found in raw.c **/
  48. extern BOOL PrintRawJob(
  49. IN PPRINTPROCESSORDATA,
  50. IN LPWSTR,
  51. IN UINT);
  52. /** Functions found in text.c **/
  53. extern BOOL PrintTextJob(
  54. IN PPRINTPROCESSORDATA,
  55. IN LPWSTR);
  56. /** Functions found in journal.c **/
  57. extern BOOL PrintJournalJob(
  58. IN PPRINTPROCESSORDATA,
  59. IN LPWSTR);
  60. /** Functions found in emf.c */
  61. extern BOOL PrintEMFJob(
  62. IN PPRINTPROCESSORDATA,
  63. IN LPWSTR);
  64. /** Functions found in support.c **/
  65. extern PUCHAR GetPrinterInfo(IN HANDLE hPrinter,
  66. IN ULONG,
  67. OUT PULONG);
  68. /*++
  69. *******************************************************************
  70. 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
  71. Routine Description:
  72. Enumerates the data types supported by the print processor.
  73. Arguments:
  74. pName =>
  75. pPrintProcessorName =>
  76. Level = level of data to return (must be 1)
  77. pDatatypes => structure array to fill in
  78. cbBuf = length of structure array in bytes
  79. pcbNeeded => buffer length copied/required
  80. pcReturned => number of structures returned
  81. Return Value:
  82. TRUE if successful
  83. FALSE if failed - caller must use GetLastError for reason
  84. *******************************************************************
  85. --*/
  86. BOOL
  87. EnumPrintProcessorDatatypes(
  88. LPWSTR pName,
  89. LPWSTR pPrintProcessorName,
  90. DWORD Level,
  91. LPBYTE pDatatypes,
  92. DWORD cbBuf,
  93. LPDWORD pcbNeeded,
  94. LPDWORD pcReturned
  95. )
  96. {
  97. DATATYPES_INFO_1 *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
  98. LPWSTR *pMyDatatypes = Datatypes;
  99. DWORD cbTotal=0;
  100. LPBYTE pEnd;
  101. /** Star assuming failed / no entries returned **/
  102. *pcReturned = 0;
  103. /** Pick up pointer to end of buffer given **/
  104. pEnd = (LPBYTE)pInfo1 + cbBuf;
  105. /** Add up the minimum buffer required **/
  106. while (*pMyDatatypes) {
  107. cbTotal += wcslen(*pMyDatatypes) * sizeof(WCHAR) + sizeof(WCHAR) +
  108. sizeof(DATATYPES_INFO_1);
  109. pMyDatatypes++;
  110. }
  111. /** Set the buffer length returned/required **/
  112. *pcbNeeded = cbTotal;
  113. /** Fill in the array only if there is sufficient space to **/
  114. if (cbTotal <= cbBuf) {
  115. /** Pick up our list of supported data types **/
  116. pMyDatatypes = Datatypes;
  117. /**
  118. Fill in the given buffer. We put the data names at the end of
  119. the buffer, working towards the front. The structures are put
  120. at the front, working towards the end.
  121. **/
  122. while (*pMyDatatypes) {
  123. pEnd -= wcslen(*pMyDatatypes)*sizeof(WCHAR) + sizeof(WCHAR);
  124. wcscpy((LPWSTR)pEnd, *pMyDatatypes);
  125. pInfo1->pName = (LPWSTR)pEnd;
  126. pInfo1++;
  127. (*pcReturned)++;
  128. pMyDatatypes++;
  129. }
  130. } else {
  131. /** Caller didn't have large enough buffer, set error and return **/
  132. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  133. return FALSE;
  134. }
  135. /** Return success **/
  136. return TRUE;
  137. }
  138. /*++
  139. *******************************************************************
  140. O p e n P r i n t P r o c e s s o r
  141. Routine Description:
  142. Arguments:
  143. pPrinterName => name of printer we are
  144. opening for
  145. pPrintProcessorOpenData => information used for opening
  146. the print processor
  147. Return Value:
  148. PPRINTPROCESSORDATA => processor data of opened
  149. processor if successful
  150. NULL if failed - caller uses GetLastError for reason
  151. NOTE: OpenPrinter will be called iff this returns a valid handle
  152. (and we're not journal)
  153. ClosePrintProcessor MUST be called if we succeed here,
  154. (or else things don't get cleaned up--like pIniJob->cRef
  155. for RAW jobs, which causes the queue to stick!)
  156. *******************************************************************
  157. --*/
  158. HANDLE
  159. OpenPrintProcessor(
  160. LPWSTR pPrinterName,
  161. PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
  162. )
  163. {
  164. PPRINTPROCESSORDATA pData;
  165. LPWSTR *pMyDatatypes=Datatypes;
  166. DWORD uDatatype=0;
  167. HANDLE hPrinter=0;
  168. HDC hDC = 0;
  169. #ifdef SPOOLKM
  170. PDEVMODEW pDevmode = NULL;
  171. #endif
  172. /** If the caller passed a NULL for the open data, fail the call **/
  173. if (!pPrintProcessorOpenData ||
  174. !pPrintProcessorOpenData->pDatatype ||
  175. !*pPrintProcessorOpenData->pDatatype) {
  176. SetLastError(ERROR_INVALID_PARAMETER);
  177. return NULL;
  178. }
  179. /** Search for the data type index we are opening for **/
  180. while (*pMyDatatypes) {
  181. if (!_wcsicmp(*pMyDatatypes,pPrintProcessorOpenData->pDatatype)) {
  182. break;
  183. }
  184. pMyDatatypes++;
  185. uDatatype++;
  186. }
  187. /** Allocate a buffer for the print processor data to return **/
  188. pData = (PPRINTPROCESSORDATA)AllocSplMem(sizeof(PRINTPROCESSORDATA));
  189. if (!pData) {
  190. OutputDebugString(L"Alloc failed");
  191. return NULL;
  192. }
  193. /** Open the processor accordingly **/
  194. switch (uDatatype) {
  195. case PRINTPROCESSOR_TYPE_RAW:
  196. case PRINTPROCESSOR_TYPE_RAW_FF:
  197. case PRINTPROCESSOR_TYPE_RAW_FF_AUTO:
  198. if (!OpenPrinter(pPrinterName, &hPrinter, NULL))
  199. goto Fail;
  200. break;
  201. #ifdef SPOOLKM
  202. case PRINTPROCESSOR_TYPE_EMF:
  203. if(pPrintProcessorOpenData->pDevMode)
  204. {
  205. if(!(pDevmode=AllocSplMem(pPrintProcessorOpenData->pDevMode->dmSize+
  206. pPrintProcessorOpenData->pDevMode->dmDriverExtra)))
  207. {
  208. goto Fail;
  209. }
  210. memcpy(pDevmode,
  211. pPrintProcessorOpenData->pDevMode,
  212. pPrintProcessorOpenData->pDevMode->dmSize+
  213. pPrintProcessorOpenData->pDevMode->dmDriverExtra);
  214. }
  215. break;
  216. #else
  217. case PRINTPROCESSOR_TYPE_JOURNAL:
  218. #endif
  219. case PRINTPROCESSOR_TYPE_TEXT:
  220. if (!(hDC = CreateDC(L"", pPrinterName, L"",
  221. pPrintProcessorOpenData->pDevMode)))
  222. goto Fail;
  223. break;
  224. default:
  225. SetLastError(ERROR_INVALID_DATATYPE);
  226. goto Fail;
  227. }
  228. /** Fill in the print processors information **/
  229. pData->cb = sizeof(PRINTPROCESSORDATA);
  230. pData->signature = PRINTPROCESSORDATA_SIGNATURE;
  231. pData->JobId = pPrintProcessorOpenData->JobId;
  232. pData->hPrinter = hPrinter;
  233. pData->semPaused = CreateEvent(NULL, FALSE, TRUE,NULL);
  234. pData->uDatatype = uDatatype;
  235. pData->hDC = hDC;
  236. pData->Copies = 1;
  237. pData->TabSize = BASE_TAB_SIZE;
  238. /** Allocate and fill in the processors strings **/
  239. pData->pPrinterName = AllocSplStr(pPrinterName);
  240. pData->pDatatype = AllocSplStr(pPrintProcessorOpenData->pDatatype);
  241. pData->pDocument = AllocSplStr(pPrintProcessorOpenData->pDocumentName);
  242. pData->pOutputFile = AllocSplStr(pPrintProcessorOpenData->pOutputFile);
  243. pData->pParameters = AllocSplStr(pPrintProcessorOpenData->pParameters);
  244. #ifdef SPOOLKM
  245. pData->pDevmode = pDevmode;
  246. #endif
  247. /**
  248. WORKWORK - BUGBUG: Currently, the pParameters field has
  249. the name of the printer driver. This will be fixed, and
  250. should come up here the same as the user submitted in the
  251. job's Printer Info structure.
  252. **/
  253. /** Parse the parameters string **/
  254. if (pData->pParameters) {
  255. ULONG value;
  256. USHORT length = sizeof(ULONG);
  257. /**
  258. Look to see if there is a COPIES=n key/value in the
  259. Parameters field of this job. This tells us the number
  260. of times to play the data.
  261. **/
  262. if (pData->pParameters) {
  263. GetKeyValue(pData->pParameters,
  264. pCopiesKey,
  265. VALUE_ULONG,
  266. &length,
  267. &value);
  268. if (length == sizeof(ULONG)) {
  269. pData->Copies = value;
  270. }
  271. }
  272. /** If this is a text job, see if the tab size is in there **/
  273. if (uDatatype == PRINTPROCESSOR_TYPE_TEXT) {
  274. USHORT length = sizeof(ULONG);
  275. GetKeyValue(pData->pParameters,
  276. pTabsKey,
  277. VALUE_ULONG,
  278. &length,
  279. &value);
  280. if ((length == sizeof(ULONG)) && value) {
  281. pData->TabSize = value;
  282. }
  283. }
  284. } /* If we have a parameter string */
  285. /**
  286. If we are doing copies, we need to check to see if
  287. this is a direct or spooled job. If it is direct, then
  288. we can't do copies because we can't rewind the data stream.
  289. **/
  290. if (pData->Copies > 1) {
  291. ULONG Error;
  292. PPRINTER_INFO_2 pPrinterInfo2;
  293. /** If we don't already have the printer open, do it **/
  294. if (uDatatype != PRINTPROCESSOR_TYPE_RAW ||
  295. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF ||
  296. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF_AUTO) {
  297. OpenPrinter(pPrinterName, &hPrinter, NULL);
  298. }
  299. if (hPrinter && hPrinter != INVALID_HANDLE_VALUE) {
  300. /** Get the printer info - this returns an allocated buffer **/
  301. pPrinterInfo2 = (PPRINTER_INFO_2)GetPrinterInfo(hPrinter, 2, &Error);
  302. /** If we couldn't get the info, be safe and don't do copies **/
  303. if (!pPrinterInfo2) {
  304. OutputDebugString(L"GetPrinter failed - falling back to 1 copy\n");
  305. pData->Copies = 1;
  306. }
  307. else {
  308. if (pPrinterInfo2->Attributes & PRINTER_ATTRIBUTE_DIRECT) {
  309. pData->Copies = 1;
  310. }
  311. FreeSplMem((PUCHAR)pPrinterInfo2);
  312. }
  313. /** If we just opened the printer, close it **/
  314. if (uDatatype != PRINTPROCESSOR_TYPE_RAW ||
  315. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF ||
  316. uDatatype != PRINTPROCESSOR_TYPE_RAW_FF_AUTO) {
  317. ClosePrinter(hPrinter);
  318. }
  319. }
  320. else {
  321. pData->Copies = 1;
  322. }
  323. }
  324. return (HANDLE)pData;
  325. Fail:
  326. if (pData) {
  327. FreeSplMem(pData);
  328. }
  329. return FALSE;
  330. }
  331. /*++
  332. *******************************************************************
  333. 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
  334. Routine Description:
  335. Arguments:
  336. hPrintProcessor
  337. pDocumentName
  338. Return Value:
  339. TRUE if successful
  340. FALSE if failed - GetLastError() will return reason
  341. *******************************************************************
  342. --*/
  343. BOOL
  344. PrintDocumentOnPrintProcessor(
  345. HANDLE hPrintProcessor,
  346. LPWSTR pDocumentName
  347. )
  348. {
  349. PPRINTPROCESSORDATA pData;
  350. /**
  351. Make sure the handle is valid and pick up
  352. the Print Processors data area.
  353. **/
  354. if (!(pData = ValidateHandle(hPrintProcessor))) {
  355. return FALSE;
  356. }
  357. /**
  358. Print the job based on its data type.
  359. **/
  360. switch (pData->uDatatype) {
  361. #ifdef SPOOLKM
  362. case PRINTPROCESSOR_TYPE_EMF:
  363. return PrintEMFJob( pData, pDocumentName );
  364. break;
  365. #else
  366. case PRINTPROCESSOR_TYPE_JOURNAL:
  367. return PrintJournalJob( pData, pDocumentName );
  368. break;
  369. #endif
  370. case PRINTPROCESSOR_TYPE_RAW:
  371. case PRINTPROCESSOR_TYPE_RAW_FF:
  372. case PRINTPROCESSOR_TYPE_RAW_FF_AUTO:
  373. return PrintRawJob(pData, pDocumentName, pData->uDatatype);
  374. break;
  375. case PRINTPROCESSOR_TYPE_TEXT:
  376. return PrintTextJob(pData, pDocumentName);
  377. break;
  378. } /* Case on data type */
  379. /** Return success **/
  380. return TRUE;
  381. }
  382. /*++
  383. *******************************************************************
  384. C l o s e P r i n t P r o c e s s o r
  385. Routine Description:
  386. Frees the resources used by an open print processor.
  387. Arguments:
  388. hPrintProcessor (HANDLE) => print processor to close
  389. Return Value:
  390. TRUE if successful
  391. FALSE if failed - caller uses GetLastError for reason.
  392. *******************************************************************
  393. --*/
  394. BOOL
  395. ClosePrintProcessor(
  396. HANDLE hPrintProcessor
  397. )
  398. {
  399. PPRINTPROCESSORDATA pData;
  400. /**
  401. Make sure the handle is valid and pick up
  402. the Print Processors data area.
  403. **/
  404. if (!(pData= ValidateHandle(hPrintProcessor))) {
  405. return FALSE;
  406. }
  407. pData->signature = 0;
  408. /* Release any allocated resources */
  409. if (pData->hPrinter)
  410. ClosePrinter(pData->hPrinter);
  411. if (pData->hDC)
  412. DeleteDC(pData->hDC);
  413. #ifdef SPOOLKM
  414. if (pData->pDevmode)
  415. FreeSplMem(pData->pDevmode);
  416. #endif
  417. CloseHandle(pData->semPaused);
  418. if (pData->pPrinterName)
  419. FreeSplStr(pData->pPrinterName);
  420. if (pData->pDatatype)
  421. FreeSplStr(pData->pDatatype);
  422. if (pData->pDocument)
  423. FreeSplStr(pData->pDocument);
  424. if (pData->pOutputFile)
  425. FreeSplStr(pData->pOutputFile);
  426. if (pData->pParameters)
  427. FreeSplStr(pData->pParameters);
  428. FreeSplMem(pData);
  429. return TRUE;
  430. }
  431. /*++
  432. *******************************************************************
  433. C o n t r o l P r i n t P r o c e s s o r
  434. Routine Description:
  435. Handles commands to pause, resume, and cancel print jobs.
  436. Arguments:
  437. hPrintProcessor = HANDLE to the PrintProcessor the
  438. command is issued for.
  439. Return Value:
  440. TRUE if command succeeded
  441. FALSE if command failed (invalid command)
  442. *******************************************************************
  443. --*/
  444. BOOL
  445. ControlPrintProcessor(
  446. HANDLE hPrintProcessor,
  447. DWORD Command
  448. )
  449. {
  450. PPRINTPROCESSORDATA pData;
  451. /**
  452. Make sure the handle is valid and pick up
  453. the Print Processors data area.
  454. **/
  455. if (pData = ValidateHandle(hPrintProcessor)) {
  456. switch (Command) {
  457. case JOB_CONTROL_PAUSE:
  458. ResetEvent(pData->semPaused);
  459. pData->fsStatus |= PRINTPROCESSOR_PAUSED;
  460. return TRUE;
  461. break;
  462. case JOB_CONTROL_CANCEL:
  463. pData->fsStatus |= PRINTPROCESSOR_ABORTED;
  464. #if SPOOLKM
  465. if (pData->uDatatype == PRINTPROCESSOR_TYPE_EMF)
  466. CancelDC(pData->hDC);
  467. #else
  468. if (pData->uDatatype == PRINTPROCESSOR_TYPE_JOURNAL)
  469. CancelDC(pData->hDC);
  470. #endif
  471. /* fall through to release job if paused */
  472. case JOB_CONTROL_RESUME:
  473. if (pData->fsStatus & PRINTPROCESSOR_PAUSED) {
  474. SetEvent(pData->semPaused);
  475. pData->fsStatus &= ~PRINTPROCESSOR_PAUSED;
  476. }
  477. return TRUE;
  478. break;
  479. default:
  480. return FALSE;
  481. break;
  482. }
  483. }
  484. return FALSE;
  485. }
  486. /*++
  487. *******************************************************************
  488. I n s t a l l P r i n t P r o c e s s o r
  489. Routine Description:
  490. Arguments:
  491. Return Value:
  492. TRUE
  493. *******************************************************************
  494. --*/
  495. BOOL
  496. InstallPrintProcessor(
  497. HWND hWnd
  498. )
  499. {
  500. MessageBox(hWnd, L"WinPrint", L"Print Processor Setup", MB_OK);
  501. return TRUE;
  502. }
  503. /*++
  504. *******************************************************************
  505. V a l i d a t e H a n d l e
  506. Routine Description:
  507. Validates the given Print Processor HANDLE (which is
  508. really a pointer to the Print Processor's data) by
  509. checking for our signature.
  510. Arguments:
  511. hQProc (HANDLE) => Print Processor data structure. This
  512. is verified as really being a pointer to the Print
  513. Processor's data.
  514. Return Value:
  515. PPRINTPROCESSORDATA if successful (valid pointer passed)
  516. NULL if failed - pointer was not valid
  517. *******************************************************************
  518. --*/
  519. PPRINTPROCESSORDATA
  520. ValidateHandle(
  521. HANDLE hQProc
  522. )
  523. {
  524. /** Pick up the pointer **/
  525. PPRINTPROCESSORDATA pData = (PPRINTPROCESSORDATA)hQProc;
  526. try {
  527. /** See if our signature exists in the suspected data region **/
  528. if (pData && pData->signature != PRINTPROCESSORDATA_SIGNATURE) {
  529. /** Bad pointer - return failed **/
  530. pData = NULL;
  531. }
  532. }except (1) {
  533. /** Bad pointer - return failed **/
  534. pData = NULL;
  535. }
  536. if ( pData == NULL )
  537. SetLastError( ERROR_INVALID_HANDLE );
  538. return pData;
  539. }