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.

2160 lines
55 KiB

  1. /*
  2. Copyright (c) 1992-2000 Microsoft Corporation
  3. Module Name:
  4. psexe.c
  5. Abstract:
  6. This file contains the code required to actually communicate with the
  7. PSTODIB dll and rasterize a job. Any required information is passed via
  8. some named shared memory, the name of which is passed on the command line.
  9. This name is guaranteed to be unique to the system and thus multiple
  10. postscript jobs can be imaged at the same time.
  11. --*/
  12. #include <windows.h>
  13. #include <stdarg.h>
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <winspool.h>
  17. #include <winsplp.h>
  18. #include <prtdefs.h>
  19. #include "..\..\lib\psdiblib.h"
  20. #include "..\..\..\ti\psglobal\pstodib.h"
  21. #include "..\psprint\psshmem.h"
  22. #include "psexe.h"
  23. #include <excpt.h>
  24. #include <string.h>
  25. #include "debug.h"
  26. // By defining the following, each page is blited to the desktop this way
  27. // one can verify the interpreter is running without waiting for the printer
  28. // to print
  29. //
  30. //#define BLIT_TO_DESKTOP
  31. // By defining the following, you will cause all the code to get executed
  32. // except the part that REALLY writes to the printer. This is most useful in
  33. // conjuction with the BLIT_TO_DESKTOP so you can run the intrepeter and
  34. // have the output go to the desktop. I found this very useful during
  35. // development. It may see useful when porting to new windows NT platforms.
  36. //#define IGNORE_REAL_PRINTING
  37. // This is a hack, it should eventually be taken out, the reason this is here,
  38. // is becuse simply setting the windows page type in the DEVMODE structure,
  39. // is not good enough for the RASTER printer driver (of which most printer
  40. // drivers are based. With this table we borrowed from the spooler, we
  41. // can set the correct FORM name which the printer drivers respect and can
  42. // test different page sizes from the mac...
  43. // DJC HACK HACK
  44. PTSTR forms[] = {
  45. L"Letter",
  46. L"Letter Small",
  47. L"Tabloid",
  48. L"Ledger",
  49. L"Legal",
  50. L"Statement",
  51. L"Executive",
  52. L"A3",
  53. L"A4",
  54. L"A4 Small",
  55. L"A5",
  56. L"B4",
  57. L"B5",
  58. L"Folio",
  59. L"Quarto",
  60. L"10x14",
  61. L"11x17",
  62. L"Note",
  63. L"Envelope #9",
  64. L"Envelope #10",
  65. L"Envelope #11",
  66. L"Envelope #12",
  67. L"Envelope #14",
  68. L"C size sheet",
  69. L"D size sheet",
  70. L"E size sheet",
  71. L"Envelope DL",
  72. L"Envelope C5",
  73. L"Envelope C3",
  74. L"Envelope C4",
  75. L"Envelope C6",
  76. L"Envelope C65",
  77. L"Envelope B4",
  78. L"Envelope B5",
  79. L"Envelope B6",
  80. L"Envelope",
  81. L"Envelope Monarch",
  82. L"6 3/4 Envelope",
  83. L"US Std Fanfold",
  84. L"German Std Fanfold",
  85. L"German Legal Fanfold",
  86. NULL,
  87. };
  88. // This table translates from internal PSERR_* errors, defined in pstodib.h
  89. // to errors in the event log file that the user can see in the event viewer
  90. //
  91. typedef struct {
  92. DWORD dwOutputError;
  93. DWORD dwPsError;
  94. } PS_TRANSLATE_ERRORCODES;
  95. PS_TRANSLATE_ERRORCODES adwTranslate[] = {
  96. EVENT_PSTODIB_INIT_ACCESS, PSERR_INTERPRETER_INIT_ACCESS_VIOLATION,
  97. EVENT_PSTODIB_JOB_ACCESS, PSERR_INTERPRETER_JOB_ACCESS_VIOLATION,
  98. EVENT_PSTODIB_STRING_SEQ, PSERR_LOG_ERROR_STRING_OUT_OF_SEQUENCE,
  99. EVENT_PSTODIB_FRAME_ALLOC, PSERR_FRAME_BUFFER_MEM_ALLOC_FAILED,
  100. EVENT_PSTODIB_FONTQUERYFAIL, PSERR_FONT_QUERY_PROBLEM,
  101. EVENT_PSTODIB_INTERNAL_FONT, PSERR_EXCEEDED_INTERNAL_FONT_LIMIT,
  102. EVENT_PSTODIB_MEM_FAIL, PSERR_LOG_MEMORY_ALLOCATION_FAILURE
  103. };
  104. // Globals, this is global because the abortproc we pass in to the
  105. // graphics engine does not allow us to specify any data to pass to the
  106. // abort proc
  107. PSEXEDATA Data;
  108. /*** PsPrintCallBack
  109. *
  110. * This is the function pstodib calls whenever certain events occur
  111. *
  112. * Entry:
  113. * pPsToDib = Pointer to the current PSTODIB structure
  114. * pPsEvent = defines the event that is occuring
  115. *
  116. * Returns:
  117. * True = Event was handled, interpreter should continue execution
  118. * False = Abnormal termination, the interpreter should stop
  119. *
  120. */
  121. BOOL
  122. CALLBACK
  123. PsPrintCallBack(
  124. IN struct _PSDIBPARMS *pPsToDib,
  125. IN OUT PPSEVENTSTRUCT pPsEvent)
  126. {
  127. BOOL bRetVal=TRUE; // Success in case we dont support
  128. // Decide on a course of action based on the event passed in
  129. //
  130. switch( pPsEvent->uiEvent ) {
  131. case PSEVENT_PAGE_READY:
  132. // The data in the pPsEvent signifies the data we need to paint..
  133. // for know we will treat the data as one text item null
  134. // terminated simply for testing...
  135. //
  136. bRetVal = PsPrintGeneratePage( pPsToDib, pPsEvent );
  137. break;
  138. case PSEVENT_STDIN:
  139. // The interpreter is asking for some data so simply call
  140. // the print subsystem to try to satisfy the request
  141. //
  142. bRetVal = PsHandleStdInputRequest( pPsToDib, pPsEvent );
  143. break;
  144. case PSEVENT_SCALE:
  145. //
  146. // Here is an opportunity to modify the current transformation
  147. // matrix x and y values, this is used to image a 150 dpi job
  148. // on a 300 dpi interpreter frame.
  149. //
  150. bRetVal = PsHandleScaleEvent( pPsToDib, pPsEvent);
  151. break;
  152. case PSEVENT_ERROR_REPORT:
  153. //
  154. // End of job, there may have been errors so the psexe component
  155. // may print an error page to the target printer depending on the
  156. // extent of the errors
  157. //
  158. bRetVal = PsGenerateErrorPage( pPsToDib, pPsEvent);
  159. break;
  160. case PSEVENT_GET_CURRENT_PAGE_TYPE:
  161. //
  162. // The interpreter usually queries the current page type at
  163. // startup time, and uses this page type if the JOB did not
  164. // specifically specify a page type.
  165. //
  166. bRetVal = PsGetCurrentPageType( pPsToDib, pPsEvent);
  167. break;
  168. case PSEVENT_NON_PS_ERROR:
  169. //
  170. // Some sort of error occured, that was NOT a postscript error.
  171. // Examples might be resource allocation failure, or access to
  172. // a resource has unexpectantly ended.
  173. //
  174. bRetVal = PsLogNonPsError( pPsToDib, pPsEvent );
  175. break;
  176. }
  177. return bRetVal;
  178. }
  179. /*** PsPrintTranslateErrorCode
  180. *
  181. * This routine simply uses the error table to translate between errors
  182. * internal to pstodib dib, and errors in the macprint.exe event file
  183. * which may be reported in the event log
  184. *
  185. * Entry:
  186. * dwPsErr = PsToDib internal error number
  187. *
  188. *
  189. * Returns:
  190. * The corresponding error number in the event error file.
  191. *
  192. *
  193. */
  194. DWORD
  195. PsTranslateErrorCode(
  196. IN DWORD dwPsErr )
  197. {
  198. int i;
  199. for ( i = 0 ;i < sizeof(adwTranslate)/sizeof(adwTranslate[0]) ;i++ ) {
  200. if (dwPsErr == adwTranslate[i].dwPsError) {
  201. return( adwTranslate[i].dwOutputError);
  202. }
  203. }
  204. return ( EVENT_PSTODIB_UNDEFINED_ERROR );
  205. }
  206. /*** PsLogNonPsError
  207. *
  208. * This function logs an internal pstodib error
  209. *
  210. * Entry:
  211. * pPsToDib = Pointer to the current PSTODIB structure
  212. * pPsEvent = defines the NonPsError event structure with info
  213. * about the error that is occuring
  214. *
  215. * Returns:
  216. * True = Success, the event was logged
  217. * False = Failure could not log the error
  218. *
  219. */
  220. BOOL
  221. PsLogNonPsError(
  222. IN PPSDIBPARMS pPsToDib,
  223. IN PPSEVENTSTRUCT pPsEvent )
  224. {
  225. PPSEVENT_NON_PS_ERROR_STRUCT pPsError;
  226. PPSEXEDATA pData;
  227. LPTSTR aStrs[2];
  228. DWORD dwEventError;
  229. TCHAR atchar[10];
  230. WORD wStringCount;
  231. if (!(pData = ValidateHandle(pPsToDib->hPrivateData))) {
  232. return(FALSE);
  233. }
  234. pPsError = (PPSEVENT_NON_PS_ERROR_STRUCT) pPsEvent->lpVoid;
  235. dwEventError = PsTranslateErrorCode( pPsError->dwErrorCode);
  236. if (dwEventError == EVENT_PSTODIB_UNDEFINED_ERROR) {
  237. wsprintf( atchar,TEXT("%d"), pPsError->dwErrorCode);
  238. aStrs[1] = atchar;
  239. wStringCount = 2;
  240. }else{
  241. wStringCount = 1;
  242. }
  243. //
  244. // Set the document name so it gets recorded in the log file
  245. //
  246. aStrs[0] = pData->pDocument;
  247. PsLogEvent( dwEventError,
  248. wStringCount,
  249. aStrs,
  250. pPsError->bError ? PSLOG_ERROR : 0 );
  251. return(TRUE);
  252. }
  253. /*** PsGenerateErrorPage
  254. *
  255. * This function generates an error page showing the last few postscript
  256. * errors that occured.
  257. *
  258. * Entry:
  259. * pPsToDib = Pointer to the current PSTODIB structure
  260. * pPsEvent = defines the postscript errors that may have occured
  261. *
  262. * Returns:
  263. * True = Event was handled, interpreter should continue execution
  264. * False = Abnormal termination, the interpreter should stop
  265. *
  266. */
  267. BOOL
  268. PsGenerateErrorPage(
  269. IN PPSDIBPARMS pPsToDib,
  270. IN OUT PPSEVENTSTRUCT pPsEvent)
  271. {
  272. PPSEVENT_ERROR_REPORT_STRUCT pPsErr;
  273. PPSEXEDATA pData;
  274. BOOL bDidStartPage = FALSE;
  275. HGDIOBJ hOldFont=NULL;
  276. HGDIOBJ hNewFont=NULL;
  277. HGDIOBJ hNewBoldFont=NULL;
  278. LOGFONT lfFont;
  279. HPEN hNewPen=NULL;
  280. HPEN hOldPen=NULL;
  281. BOOL bRetVal=TRUE;
  282. int iCurXPos;
  283. int iCurYPos;
  284. int i;
  285. TEXTMETRIC tm;
  286. int iYMove;
  287. PCHAR pChar;
  288. int iLen;
  289. LPJOB_INFO_1 lpJob1 = NULL;
  290. DWORD dwRequired;
  291. SIZE UserNameSize;
  292. HGDIOBJ hStockFont;
  293. if (!(pData = ValidateHandle(pPsToDib->hPrivateData))) {
  294. return(FALSE);
  295. }
  296. //
  297. // Clean up access to our error struct for easier access
  298. //
  299. pPsErr = (PPSEVENT_ERROR_REPORT_STRUCT) pPsEvent->lpVoid;
  300. //
  301. // Only report the error page if there are actual errors and ONLY
  302. // if the job had a FLUSHING mode, ie the error was critical enough
  303. // to dump the rest of the postscript job. This is done becuase
  304. // some jobs have warnings, but they are not fatal and the jobs actually
  305. // print fine, there is no need to confuse the user with an error page
  306. // if the job came out fine.
  307. //
  308. if( pPsErr->dwErrCount &&
  309. (pPsErr->dwErrFlags & PSEVENT_ERROR_REPORT_FLAG_FLUSHING )) {
  310. //
  311. // Set up a do, so we can break out of any errors without using a
  312. // goto.
  313. //
  314. do {
  315. if (!GetJob( pData->hPrinter,
  316. pData->JobId,
  317. 1,
  318. (LPBYTE) NULL,
  319. 0,
  320. &dwRequired)) {
  321. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) {
  322. // Get some memory
  323. lpJob1 = (LPJOB_INFO_1) LocalAlloc( LPTR, dwRequired);
  324. if (lpJob1) {
  325. if (!GetJob(pData->hPrinter,
  326. pData->JobId, 1,
  327. (LPBYTE) lpJob1,
  328. dwRequired,
  329. &dwRequired)) {
  330. LocalFree( (HLOCAL) lpJob1 );
  331. lpJob1 = NULL;
  332. }
  333. }
  334. }
  335. }
  336. // Verify that we have a DC created!!!
  337. if( !PsVerifyDCExistsAndCreateIfRequired( pData )) {
  338. bRetVal = FALSE;
  339. break;
  340. }
  341. if( StartPage( pData->hDC ) <= 0 ) {
  342. bRetVal = FALSE;
  343. break;
  344. }
  345. bDidStartPage = TRUE;
  346. SetMapMode( pData->hDC, MM_LOENGLISH );
  347. hStockFont = GetStockObject( ANSI_VAR_FONT );
  348. if (hStockFont == (HGDIOBJ) NULL) {
  349. bRetVal = FALSE;
  350. break;
  351. }
  352. if( GetObject( hStockFont,
  353. sizeof(lfFont),
  354. (LPVOID) &lfFont) == 0 ) {
  355. bRetVal = FALSE;
  356. break;
  357. }
  358. //
  359. // Create the error item font in the correct size
  360. //
  361. lfFont.lfHeight = PS_ERR_FONT_SIZE;
  362. lfFont.lfWidth = 0;
  363. hNewFont = CreateFontIndirect( &lfFont);
  364. if (hNewFont == (HFONT) NULL) {
  365. bRetVal = FALSE;
  366. break;
  367. }
  368. // Create the error Header font
  369. //
  370. lfFont.lfHeight = PS_ERR_HEADER_FONT_SIZE;
  371. lfFont.lfWeight = FW_BOLD;
  372. hNewBoldFont = CreateFontIndirect( &lfFont );
  373. if (hNewBoldFont == (HFONT) NULL) {
  374. bRetVal = FALSE;
  375. break;
  376. }
  377. hOldFont = SelectObject( pData->hDC, hNewBoldFont);
  378. if (hOldFont == (HFONT)NULL) {
  379. bRetVal = FALSE;
  380. break;
  381. }
  382. if (!GetTextMetrics(pData->hDC, &tm)) {
  383. bRetVal = FALSE;
  384. break;
  385. }
  386. //
  387. // Set up how much to move vertically for positioning each line
  388. //
  389. iYMove = tm.tmHeight + tm.tmExternalLeading;
  390. //
  391. // Set the starting positiongs
  392. //
  393. iCurXPos = PS_INCH;
  394. iCurYPos = -PS_INCH;
  395. //
  396. // If we have info about the job then show it
  397. //
  398. if (lpJob1) {
  399. if (lpJob1->pUserName != NULL) {
  400. if (!GetTextExtentPoint( pData->hDC,
  401. lpJob1->pUserName,
  402. lstrlen(lpJob1->pUserName),
  403. &UserNameSize) ) {
  404. bRetVal = FALSE;
  405. break;
  406. }
  407. if( !TextOut( pData->hDC,
  408. iCurXPos,
  409. iCurYPos,
  410. lpJob1->pUserName,
  411. lstrlen(lpJob1->pUserName))) {
  412. bRetVal = FALSE;
  413. break;
  414. }
  415. }else{
  416. UserNameSize.cx = 0;
  417. UserNameSize.cy = 0;
  418. }
  419. if (lpJob1->pDocument != NULL) {
  420. if( !TextOut( pData->hDC,
  421. iCurXPos + PS_QUART_INCH + UserNameSize.cx,
  422. iCurYPos,
  423. lpJob1->pDocument,
  424. lstrlen(lpJob1->pDocument))) {
  425. bRetVal = FALSE;
  426. break;
  427. }
  428. }
  429. }
  430. //
  431. // Adjust the current position
  432. //
  433. iCurYPos -= (iYMove + PS_ERR_LINE_WIDTH );
  434. // Draw A nice line
  435. //
  436. hNewPen = CreatePen( PS_SOLID, PS_ERR_LINE_WIDTH, RGB(0,0,0));
  437. if (hNewPen == (HPEN) NULL ) {
  438. bRetVal = FALSE;
  439. break;
  440. }
  441. // Make our new pen active
  442. //
  443. hOldPen = SelectObject( pData->hDC, hNewPen );
  444. // Draw the line
  445. //
  446. MoveToEx( pData->hDC, iCurXPos, iCurYPos, NULL);
  447. LineTo( pData->hDC, iCurXPos + PS_ERR_LINE_LEN, iCurYPos);
  448. // Put the old pen back
  449. //
  450. SelectObject( pData->hDC, hOldPen);
  451. // Delete the pen we created
  452. //
  453. DeleteObject( hNewPen );
  454. // Reset the line
  455. //
  456. iCurYPos -= PS_ERR_LINE_WIDTH;
  457. // Now Select the normal font
  458. //
  459. SelectObject( pData->hDC, hNewFont);
  460. // Get the updated text metrics for the new font
  461. //
  462. if (!GetTextMetrics(pData->hDC, &tm)){
  463. bRetVal = FALSE;
  464. break;
  465. }
  466. iYMove = tm.tmHeight + tm.tmExternalLeading;
  467. // Now display each of the errors that came from PSTODIB
  468. //
  469. i = (int) pPsErr->dwErrCount;
  470. while (--i) {
  471. pChar = pPsErr->paErrs[i];
  472. iLen = lstrlenA( pChar );
  473. if ( !TextOutA( pData->hDC,
  474. iCurXPos,
  475. iCurYPos,
  476. pChar,
  477. iLen)) {
  478. bRetVal = FALSE;
  479. break;
  480. }
  481. iCurYPos -= (iYMove + iYMove / 3);
  482. }
  483. break;
  484. } while ( 1 );
  485. if (!bRetVal) {
  486. PsLogEventAndIncludeLastError(EVENT_PSTODIB_ERROR_STARTPG_FAIL,TRUE);
  487. }
  488. // Clenup the DC.
  489. //
  490. if (hOldFont != (HFONT) NULL) {
  491. SelectObject( pData->hDC, hOldFont);
  492. }
  493. if (hNewFont != (HFONT) NULL) {
  494. DeleteObject( hNewFont);
  495. }
  496. if (hNewBoldFont != (HFONT)NULL) {
  497. DeleteObject( hNewBoldFont );
  498. }
  499. if (bDidStartPage) {
  500. EndPage( pData->hDC );
  501. }
  502. // Free the job info memory if we had any
  503. if (lpJob1) {
  504. LocalFree((HLOCAL) lpJob1);
  505. }
  506. }
  507. return(bRetVal);
  508. }
  509. /*** PsHandleScaleEvent
  510. *
  511. * This function handles scaling the current transformation matrix
  512. * (the way logical units are mapped to device units in the interpreter) in
  513. * order to simulate different page sizes for non 300 dpi devices. this
  514. * done by scaling the transformation matrix such that only the portion
  515. * of the frame buffer which can be transfered to the target printer is used.
  516. * for example if we were going to a 150 dpi device then exactly half of
  517. * 300 dpi frame buffer would be showable on the 150 dpi device, the rest of the
  518. * frame buffer would be useless as it would extend beyond the imageable area
  519. * of the printer. Thus if we scaled the current tranformation matrix by the
  520. * ration of the target device resolution over 300 (the default pstodib resolution)
  521. * then graphic objects that used to be 8 inches would now be 4 and thus take
  522. * up HALF the space they used to.
  523. *
  524. * errors that occured.
  525. *
  526. * Entry:
  527. * pPsToDib = Pointer to the current PSTODIB structure
  528. * pPsEvent = defines the current scale information for the current
  529. * postscript tranformation matrix
  530. *
  531. * Returns:
  532. * True = This can never fail
  533. *
  534. */
  535. BOOL
  536. PsHandleScaleEvent(
  537. IN PPSDIBPARMS pPsToDib,
  538. IN OUT PPSEVENTSTRUCT pPsEvent)
  539. {
  540. PPS_SCALE pScale;
  541. pScale = (PPS_SCALE) pPsEvent->lpVoid;
  542. pScale->dbScaleX = (double) pPsToDib->uiXDestRes / (double) pScale->uiXRes;
  543. pScale->dbScaleY = (double) pPsToDib->uiYDestRes / (double) pScale->uiYRes;
  544. #ifdef BLIT_TO_DESKTOP
  545. pScale->dbScaleX *= .25;
  546. pScale->dbScaleY *= .25;
  547. #endif
  548. return(TRUE);
  549. }
  550. /*** ValidateHandle
  551. *
  552. * Validates the handle passed in to make sure its correct, if its not
  553. * it also logs an error.
  554. *
  555. *
  556. * Entry:
  557. * hQProc = Handle to data block
  558. *
  559. * Returns:
  560. * A valid ptr to a session block.
  561. * NULL - failure the handle passed in was not what was expected.
  562. */
  563. PPSEXEDATA
  564. ValidateHandle(
  565. HANDLE hQProc
  566. )
  567. {
  568. PPSEXEDATA pData = (PPSEXEDATA)hQProc;
  569. if (pData && pData->signature == PSEXE_SIGNATURE) {
  570. return( pData );
  571. } else {
  572. //
  573. // Log an error so we know something is wrong
  574. //
  575. PsLogEvent( EVENT_PSTODIB_LOG_INVALID_HANDLE,
  576. 0,
  577. NULL,
  578. PSLOG_ERROR );
  579. DBGOUT(("Validate handle failed..."));
  580. return( (PPSEXEDATA) NULL );
  581. }
  582. }
  583. /*** PsHandleStdInputRequest
  584. *
  585. * This function handles std input requests from the interpreter by reading
  586. * more data from the Win32 spooler.
  587. *
  588. *
  589. * Entry:
  590. * pPsToDib = Pointer to the current PSTODIB structure
  591. * pPsEvent = A pointer to a structure that defines where to put the
  592. * newly acquired data
  593. *
  594. * Returns:
  595. * True = Success
  596. * FALSE = Failure the interepreter should stop processing postscript upon
  597. * return from this function.
  598. */
  599. BOOL
  600. PsHandleStdInputRequest(
  601. IN PPSDIBPARMS pPsToDib,
  602. IN OUT PPSEVENTSTRUCT pPsEvent)
  603. {
  604. PPSEXEDATA pData;
  605. PPSEVENT_STDIN_STRUCT pStdinStruct;
  606. DWORD dwAmtToCopy;
  607. if (!(pData = ValidateHandle(pPsToDib->hPrivateData))) {
  608. return FALSE;
  609. }
  610. //
  611. // No matter what check for block or abort
  612. //
  613. if ( PsCheckForWaitAndAbort( pData )) {
  614. return(FALSE);
  615. }
  616. //
  617. // Cast the data to the correct structure
  618. //
  619. pStdinStruct = (PPSEVENT_STDIN_STRUCT) pPsEvent->lpVoid;
  620. //
  621. // Look to see if we have any data left over from our cache...
  622. // if so return that data instead of really reading from the spooler
  623. //
  624. if (pData->cbBinaryBuff != 0) {
  625. //
  626. // A little bit of math here in case the buffer passed in to
  627. // us is not big enough to hold the entire cache buffer
  628. //
  629. dwAmtToCopy = min( pData->cbBinaryBuff, pStdinStruct->dwBuffSize);
  630. //
  631. // There is data so lets copy it first...
  632. //
  633. memcpy( pStdinStruct->lpBuff,
  634. pData->lpBinaryPosToReadFrom,
  635. dwAmtToCopy );
  636. //
  637. // Now upate the pointer and counts;
  638. //
  639. pData->cbBinaryBuff -= dwAmtToCopy;
  640. pData->lpBinaryPosToReadFrom += dwAmtToCopy;
  641. pStdinStruct->dwActualBytes = dwAmtToCopy;
  642. }else{
  643. //
  644. // Read from the printer the amount of data the interpreter
  645. // claims he can handle
  646. //
  647. if( !ReadPrinter( pData->hPrinter,
  648. pStdinStruct->lpBuff,
  649. pStdinStruct->dwBuffSize,
  650. &(pStdinStruct->dwActualBytes ))) {
  651. //
  652. // something is wrong... so reset the bytes read to 0
  653. //
  654. pStdinStruct->dwActualBytes = 0;
  655. //
  656. // If something unexpected happened log it
  657. //
  658. if (GetLastError() != ERROR_PRINT_CANCELLED) {
  659. //
  660. // Something happened... log it and abort
  661. //
  662. PsLogEventAndIncludeLastError(EVENT_PSTODIB_GET_DATA_FAILED,TRUE);
  663. }
  664. }
  665. }
  666. // If the number of bytes returned is 0 then were done...
  667. //
  668. if (pStdinStruct->dwActualBytes == 0) {
  669. // we read nothing from the file... declare an EOF
  670. pStdinStruct->uiFlags |= PSSTDIN_FLAG_EOF;
  671. }
  672. return(TRUE);
  673. }
  674. /*** PsCheckForWaitAndAbort
  675. *
  676. * This function checks to see if the user
  677. * more data from the Win32 spooler.
  678. *
  679. *
  680. * Entry:
  681. * pData = A pointer to our current job structure
  682. *
  683. * Returns:
  684. * True = An abort has been requested
  685. * False = Ok, normal processing
  686. */
  687. BOOL
  688. PsCheckForWaitAndAbort(
  689. IN PPSEXEDATA pData )
  690. {
  691. BOOL bRetVal = FALSE;
  692. // 1st verify we are not blocked... if we are, wait for the
  693. // semaphore before continuing since someone decided to PAUSE us
  694. //
  695. WaitForSingleObject(pData->semPaused, INFINITE);
  696. // Check the ABORT flag that would have been sent if the user aborted
  697. // us from printman
  698. //
  699. bRetVal = *(pData->pdwFlags) & PS_SHAREDMEM_ABORTED;
  700. #ifdef MYPSDEBUG
  701. if (bRetVal) {
  702. DBGOUT(("\nAbort requested...."));
  703. }
  704. #endif
  705. return(bRetVal);
  706. }
  707. /*** PsSetPrintingInfo
  708. *
  709. * This function brings the current devmode structure up to date, based
  710. * on number of copies and or current page type to use for the next
  711. * page.
  712. *
  713. *
  714. * Entry:
  715. * pData = Pointer to the current job data structure
  716. * ppsPage = A pointer to a structure that defines the current page
  717. * to image, based on data from the intrepreter.
  718. *
  719. * Returns:
  720. * True = A change occured, the devmode has been made up to date, and
  721. * somethign changed (signals that ResetDC should be called.
  722. *
  723. * False = Ok, no changes were observed
  724. */
  725. BOOL
  726. PsSetPrintingInfo(
  727. IN OUT PPSEXEDATA pData,
  728. IN PPSEVENT_PAGE_READY_STRUCT ppsPage )
  729. {
  730. BOOL bRetVal = FALSE;
  731. LPDEVMODE lpDevmode;
  732. lpDevmode = pData->printEnv.lpDevmode;
  733. if (lpDevmode != (LPDEVMODE) NULL ) {
  734. // We have a devmode so go ahead and look for changes
  735. if (lpDevmode->dmFields & DM_PAPERSIZE) {
  736. if (lpDevmode->dmPaperSize != ppsPage->iWinPageType) {
  737. lpDevmode->dmPaperSize = (short)(ppsPage->iWinPageType);
  738. bRetVal = TRUE;
  739. }
  740. }
  741. // HACKHACK DJCTEST hack hack , until page stuff gets resolved
  742. // once we can simply pass a new page type in this code will go away
  743. //
  744. if (lpDevmode->dmFields & DM_FORMNAME) {
  745. if (wcscmp( forms[ppsPage->iWinPageType-1], lpDevmode->dmFormName)) {
  746. wcscpy( lpDevmode->dmFormName, forms[ppsPage->iWinPageType-1]);
  747. bRetVal = TRUE;
  748. }
  749. }
  750. // DJC end hack....
  751. // DJC need a decision here because if the driver does not support
  752. // multiple copies we need to simulate it ????
  753. if (lpDevmode->dmFields & DM_COPIES) {
  754. if (lpDevmode->dmCopies != (short) ppsPage->uiCopies) {
  755. lpDevmode->dmCopies = (short)(ppsPage->uiCopies);
  756. bRetVal = TRUE;
  757. }
  758. }
  759. }
  760. return( bRetVal );
  761. }
  762. /*** PsPrintGeneratePage
  763. *
  764. * This function is called whenever the interpreter gets a showpage
  765. * and is responsible for managing the DC of the printer we are currently
  766. * printing to.
  767. *
  768. * Entry:
  769. * pPsToDib = Pointer to the current PSTODIB structure
  770. * pPsEvent = A pointer to a structure that defines the attributes for
  771. * the frame buffer which is ready to be imaged. This function
  772. * will verify that we are not paused/aborted, verify a device
  773. * context is available to draw into,
  774. * double check and
  775. * update the current DEVMODE, reset the DC if required and
  776. * finally call the code to actualy draw the frame buffer.
  777. *
  778. * Returns:
  779. * True = Success
  780. * FALSE = Failure the interepreter should stop processing postscript upon
  781. * return from this function.
  782. */
  783. BOOL
  784. PsPrintGeneratePage(
  785. IN PPSDIBPARMS pPsToDib,
  786. IN PPSEVENTSTRUCT pPsEvent)
  787. {
  788. PPSEXEDATA pData;
  789. PPSEVENT_PAGE_READY_STRUCT ppsPageReady;
  790. if (!(pData = ValidateHandle(pPsToDib->hPrivateData))) {
  791. // do something here,,,, we have a major problem...
  792. return(FALSE);
  793. }
  794. // Verify were not aborting....
  795. if ( PsCheckForWaitAndAbort( pData)) {
  796. return(FALSE);
  797. }
  798. ppsPageReady = (PPSEVENT_PAGE_READY_STRUCT) pPsEvent->lpVoid;
  799. // Verify that the current set of data were imaging under is correct
  800. // If not lets set it up so it is, PAGE_SIZE, COPIES for now
  801. if (PsSetPrintingInfo( pData, ppsPageReady) &&
  802. (pData->hDC != (HDC)NULL )) {
  803. DBGOUT(("\nReseting the DC"));
  804. if( ResetDC( pData->hDC, pData->printEnv.lpDevmode) == (HDC) NULL ) {
  805. PsLogEventAndIncludeLastError(EVENT_PSTODIB_RESETDC_FAILED,FALSE);
  806. }
  807. }
  808. // We may not have a dc set up yet, in this case we need to create it
  809. // with the new devmode data we just modified. If we do this then
  810. // we dont need to do a reset dc.
  811. #ifndef IGNORE_REAL_PRINTING
  812. if(!PsVerifyDCExistsAndCreateIfRequired( pData )) {
  813. return(FALSE);
  814. }
  815. #endif
  816. // Everything is ready to actuall image the frame buffer to the Target
  817. // device context, so do it...
  818. //
  819. return PsPrintStretchTheBitmap( pData, ppsPageReady );
  820. }
  821. /*** PsPrintStretchTheBitmap
  822. *
  823. * This function actually manages the target surface and either blits or
  824. * stretchBlits (based on the resolution of the target printer) the frame
  825. * buffer.
  826. *
  827. * Entry:
  828. * pData = Pointer to the current job structure
  829. * ppsPageReady = Pointer to the page ready event structure that
  830. * the pstodib component prepared for us..
  831. * Returns:
  832. * True = Success
  833. * FALSE = Failure the interepreter should stop processing postscript upon
  834. * return from this function.
  835. */
  836. BOOL
  837. PsPrintStretchTheBitmap(
  838. IN PPSEXEDATA pData,
  839. IN PPSEVENT_PAGE_READY_STRUCT ppsPageReady )
  840. {
  841. BOOL bOk = TRUE;
  842. int iXres, iYres;
  843. int iDestWide, iDestHigh;
  844. int iPageCount;
  845. int iYOffset;
  846. int iXSrc;
  847. int iYSrc;
  848. int iNumPagesToPrint;
  849. int iBlit;
  850. int iNewY;
  851. int iNewX;
  852. // Now do some calculations so we decide if we really need to
  853. // stretch the bitmap or not. If the true resolution of the target
  854. // printer is less than pstodibs (PSTDOBI_*_DPI) then we will shring
  855. // the effective area so we actually only grab a portion of the bitmap
  856. // However if the Target DPI is greater that PSTODIBS there is nothing
  857. // we can do other than actually stretch (grow) the bitmap.
  858. //
  859. #ifndef BLIT_TO_DESKTOP
  860. iXres = GetDeviceCaps(pData->hDC, LOGPIXELSX);
  861. iYres = GetDeviceCaps(pData->hDC, LOGPIXELSY);
  862. #else
  863. iXres = 300;
  864. iYres = 300;
  865. #endif
  866. // Get the DPI of the target dc anc calculate how much of the frame buffer
  867. // we must want in order to show the page correctly
  868. //
  869. iDestWide = (ppsPageReady->dwWide * iXres) / PSTODIB_X_DPI;
  870. iDestHigh = (ppsPageReady->dwHigh * iYres) / PSTODIB_Y_DPI;
  871. // If the resolution of the target printer is larger that the resolution
  872. // of the interpreter, then were forced to actually stretch the data, so
  873. // we can fill the page
  874. //
  875. if (iDestHigh > (int) ppsPageReady->dwHigh ) {
  876. iYSrc = ppsPageReady->dwHigh;
  877. iYOffset = 0;
  878. } else {
  879. iYSrc = iDestHigh;
  880. iYOffset = ppsPageReady->dwHigh - iDestHigh;
  881. }
  882. if (iDestWide > (int) ppsPageReady->dwWide) {
  883. iXSrc = ppsPageReady->dwWide;
  884. } else {
  885. iXSrc = iDestWide;
  886. }
  887. // Set up the number of pages to print, if the printer driver does not
  888. // support multiple pages on its own we need to simulate it...
  889. //
  890. if ((pData->printEnv.lpDevmode == (LPDEVMODE) NULL ) ||
  891. !(pData->printEnv.lpDevmode->dmFields & DM_COPIES )) {
  892. iNumPagesToPrint = ppsPageReady->uiCopies;
  893. DBGOUT(("\nSimulating copies settting to %d", iNumPagesToPrint));
  894. } else {
  895. DBGOUT(("\nUsing devmode copies of %d", pData->printEnv.lpDevmode->dmCopies));
  896. iNumPagesToPrint = 1; // The driver will do it for us
  897. }
  898. //
  899. // Set the starting point of the image so we respect the fact that
  900. // postscript jobs have 0,0 at the bottom of the page and grow upwards
  901. // based on this info we need to compare the imageable area of the
  902. // device context and determine how much we need to offset the top,left
  903. // corner of our image such that the bottom of our image lines up with the
  904. // bottom of the REAL imageable area of the device. This is our best hope
  905. // of having the image appear in the correct place on the page.
  906. //
  907. iNewX = (GetDeviceCaps( pData->hDC, HORZRES) - iDestWide) / 2;
  908. iNewY = (GetDeviceCaps( pData->hDC, VERTRES) - iDestHigh) / 2;
  909. // If the printer driver does not support multiple copies then we need
  910. // to handle appropriately
  911. //
  912. for ( iPageCount = 0 ;
  913. iPageCount < iNumPagesToPrint ;
  914. iPageCount++ ) {
  915. #ifndef IGNORE_REAL_PRINTING
  916. if (StartPage( pData->hDC) <= 0 ) {
  917. PsLogEventAndIncludeLastError(EVENT_PSTODIB_FAIL_IMAGE,TRUE);
  918. bOk = FALSE;
  919. break;
  920. }
  921. #endif
  922. #ifdef BLIT_TO_DESKTOP
  923. {
  924. HDC hDC;
  925. //TEST DJC, sanity
  926. hDC = GetDC(GetDesktopWindow());
  927. SetStretchBltMode( hDC, BLACKONWHITE);
  928. StretchDIBits ( hDC,
  929. 0,
  930. 0,
  931. iDestWide,
  932. iDestHigh,
  933. 0,
  934. iYOffset,
  935. iXSrc,
  936. iYSrc,
  937. (LPVOID) ppsPageReady->lpBuf,
  938. ppsPageReady->lpBitmapInfo,
  939. DIB_RGB_COLORS,
  940. SRCCOPY );
  941. ReleaseDC(GetDesktopWindow(), hDC);
  942. }
  943. #endif
  944. #ifdef MYPSDEBUG
  945. printf("\nDevice True size wxh %d,%d", GetDeviceCaps(pData->hDC,HORZRES),
  946. GetDeviceCaps(pData->hDC,VERTRES));
  947. printf("\nDevice Res %d x %d stretching from %d x %d, to %d x %d\nTo location %d %d",
  948. iXres,
  949. iYres,
  950. iXSrc,
  951. iYSrc,
  952. iDestWide,
  953. iDestHigh,
  954. iNewX,
  955. iNewY);
  956. #endif
  957. #ifndef IGNORE_REAL_PRINTING
  958. #ifdef MYPSDEBUG
  959. {
  960. TCHAR szBuff[512];
  961. wsprintf( szBuff,
  962. TEXT("PSTODIB True device res %d x %d, Job:%ws"),
  963. GetDeviceCaps(pData->hDC,HORZRES),
  964. GetDeviceCaps(pData->hDC,VERTRES),
  965. pData->pDocument );
  966. TextOut( pData->hDC, 0 , 0, szBuff,lstrlen(szBuff));
  967. }
  968. #endif
  969. // Set the stretch mode in case we really stretch
  970. //
  971. SetStretchBltMode( pData->hDC, BLACKONWHITE);
  972. //
  973. // Do a check to keep the stretch from occuring unless it HAS to
  974. //
  975. if ((iDestWide == iXSrc) &&
  976. (iDestHigh == iYSrc) ) {
  977. iBlit = SetDIBitsToDevice( pData->hDC,
  978. iNewX,
  979. iNewY,
  980. iDestWide,
  981. iDestHigh,
  982. 0,
  983. iYOffset,
  984. 0,
  985. ppsPageReady->dwHigh,
  986. (LPVOID) ppsPageReady->lpBuf,
  987. ppsPageReady->lpBitmapInfo,
  988. DIB_RGB_COLORS );
  989. } else {
  990. iBlit = StretchDIBits( pData->hDC,
  991. iNewX,
  992. iNewY,
  993. iDestWide,
  994. iDestHigh,
  995. 0,
  996. iYOffset,
  997. iXSrc,
  998. iYSrc,
  999. (LPVOID) ppsPageReady->lpBuf,
  1000. ppsPageReady->lpBitmapInfo,
  1001. DIB_RGB_COLORS,
  1002. SRCCOPY );
  1003. }
  1004. if( iBlit == GDI_ERROR ){
  1005. PsLogEventAndIncludeLastError(EVENT_PSTODIB_FAIL_IMAGE,TRUE);
  1006. bOk = FALSE;
  1007. break;
  1008. }
  1009. #endif
  1010. #ifndef IGNORE_REAL_PRINTING
  1011. if ( EndPage( pData->hDC ) < 0 ) {
  1012. PsLogEventAndIncludeLastError(EVENT_PSTODIB_FAIL_IMAGE,TRUE);
  1013. bOk = FALSE;
  1014. break;
  1015. }
  1016. #endif
  1017. }
  1018. return(bOk);
  1019. }
  1020. VOID
  1021. PsLogEventAndIncludeLastError(
  1022. IN DWORD dwErrorEvent,
  1023. IN BOOL bError )
  1024. {
  1025. TCHAR atBuff[20];
  1026. TCHAR *aStrs[2];
  1027. wsprintf( atBuff,TEXT("%d"), GetLastError());
  1028. aStrs[0] = atBuff;
  1029. PsLogEvent( dwErrorEvent,
  1030. 1,
  1031. aStrs,
  1032. PSLOG_ERROR );
  1033. }
  1034. /*** PsVerifyDCExistsAndCreateIfRequired
  1035. *
  1036. *
  1037. * This function checks to see if a DC already exists, and if it does not
  1038. * then it creates one with the current devmode.
  1039. *
  1040. * Entry:
  1041. * pData = Pointer to the current job structure
  1042. *
  1043. * Returns:
  1044. * True = Success
  1045. * FALSE = Failure the interepreter should stop processing postscript upon
  1046. * return from this function.
  1047. */
  1048. BOOL
  1049. PsVerifyDCExistsAndCreateIfRequired(
  1050. IN OUT PPSEXEDATA pData )
  1051. {
  1052. BOOL bRetVal = TRUE;
  1053. DOCINFO docInfo;
  1054. //
  1055. // We will only create a dc if it has not already done so
  1056. //
  1057. if (pData->hDC == (HDC) NULL ) {
  1058. pData->hDC = CreateDC(TEXT(""),
  1059. (LPCTSTR) pData->pPrinterName,
  1060. TEXT(""),
  1061. pData->printEnv.lpDevmode );
  1062. if (pData->hDC == (HDC) NULL) {
  1063. PsLogEventAndIncludeLastError( EVENT_PSTODIB_CANNOT_CREATE_DC,TRUE );
  1064. return(FALSE);
  1065. }
  1066. // Now set the abort proc, this proc will be called occasioanly by the
  1067. // system to see if we want to abort.....
  1068. //
  1069. SetAbortProc( pData->hDC, (ABORTPROC)PsPrintAbortProc );
  1070. docInfo.cbSize = sizeof(DOCINFO);
  1071. docInfo.lpszDocName = pData->pDocument;
  1072. docInfo.lpszOutput = NULL;
  1073. if ( StartDoc( pData->hDC, &docInfo) == SP_ERROR ) {
  1074. PsLogEventAndIncludeLastError( EVENT_PSTODIB_CANNOT_DO_STARTDOC,TRUE );
  1075. return(FALSE);
  1076. }
  1077. //
  1078. // Set a flag saying we did the startdoc, this is so we can
  1079. // return an error to the spooler if we did not, and force
  1080. // deletion of the job
  1081. //
  1082. pData->printEnv.dwFlags |= PS_PRINT_STARTDOC_INITIATED;
  1083. }
  1084. return( TRUE );
  1085. }
  1086. /*** PsGetDefaultDevmode
  1087. *
  1088. *
  1089. * This function retrieves the current default DEVMODE for the printer
  1090. * we are asked to image a job on.
  1091. *
  1092. * Entry:
  1093. * pData = Pointer to the current job structure
  1094. *
  1095. * Returns:
  1096. * True = Success
  1097. * FALSE = Failure the interepreter should stop processing postscript upon
  1098. * return from this function.
  1099. */
  1100. BOOL
  1101. PsGetDefaultDevmode(
  1102. IN OUT PPSEXEDATA pData )
  1103. {
  1104. DWORD dwMemRequired;
  1105. PRINTER_INFO_2 *pPrinterInfo;
  1106. if( !GetPrinter( pData->hPrinter,
  1107. 2,
  1108. (LPBYTE) NULL,
  1109. 0,
  1110. &dwMemRequired ) &&
  1111. GetLastError() != ERROR_INSUFFICIENT_BUFFER ) {
  1112. PsLogEventAndIncludeLastError( EVENT_PSTODIB_GETDEFDEVMODE_FAIL,TRUE );
  1113. return(FALSE);
  1114. }
  1115. pPrinterInfo = (PRINTER_INFO_2 *) LocalAlloc( LPTR, dwMemRequired );
  1116. if (pPrinterInfo == (PRINTER_INFO_2 *) NULL) {
  1117. PsLogEvent( EVENT_PSTODIB_MEM_ALLOC_FAILURE,
  1118. 0,
  1119. NULL,
  1120. 0 );
  1121. return(FALSE);
  1122. }
  1123. if ( !GetPrinter( pData->hPrinter,
  1124. 2,
  1125. (LPBYTE) pPrinterInfo,
  1126. dwMemRequired,
  1127. &dwMemRequired ) ) {
  1128. LocalFree( (HLOCAL) pPrinterInfo );
  1129. PsLogEventAndIncludeLastError( EVENT_PSTODIB_GETDEFDEVMODE_FAIL,TRUE );
  1130. return(FALSE);
  1131. }
  1132. dwMemRequired = DocumentProperties( (HWND) NULL,
  1133. pData->hPrinter,
  1134. pPrinterInfo->pPrinterName,
  1135. NULL,
  1136. NULL,
  1137. 0 );
  1138. pData->printEnv.lpDevmode = (LPDEVMODE) LocalAlloc( LPTR, dwMemRequired );
  1139. if (pData->printEnv.lpDevmode == (LPDEVMODE) NULL) {
  1140. LocalFree( (HLOCAL) pPrinterInfo );
  1141. PsLogEvent( EVENT_PSTODIB_MEM_ALLOC_FAILURE,
  1142. 0,
  1143. NULL,
  1144. 0 );
  1145. return(FALSE);
  1146. } else {
  1147. DocumentProperties( (HWND) NULL,
  1148. pData->hPrinter,
  1149. pPrinterInfo->pPrinterName,
  1150. pData->printEnv.lpDevmode,
  1151. NULL,
  1152. DM_COPY );
  1153. pData->printEnv.dwFlags |= PS_PRINT_FREE_DEVMODE;
  1154. }
  1155. LocalFree( (HLOCAL) pPrinterInfo );
  1156. return(TRUE);
  1157. }
  1158. /*** PsGetCurrentPageType
  1159. *
  1160. *
  1161. * This function retrieves the current pagetype based on what was
  1162. * initially in the devmode.
  1163. *
  1164. * Entry:
  1165. * pData = Pointer to the current job structure
  1166. * pPsEvent = Pointer to the structure which contains the default
  1167. * page type to use...
  1168. *
  1169. * Returns:
  1170. * True = Success
  1171. * False = The interpreter should stop processing the current job
  1172. *
  1173. */
  1174. BOOL
  1175. PsGetCurrentPageType(
  1176. IN PPSDIBPARMS pPsToDib,
  1177. IN OUT PPSEVENTSTRUCT pPsEvent)
  1178. {
  1179. PPSEXEDATA pData;
  1180. PPSEVENT_CURRENT_PAGE_STRUCT ppsCurPage;
  1181. LPDEVMODE lpDevmode;
  1182. if (!(pData = ValidateHandle(pPsToDib->hPrivateData))) {
  1183. return(FALSE);
  1184. }
  1185. ppsCurPage = (PPSEVENT_CURRENT_PAGE_STRUCT) pPsEvent->lpVoid;
  1186. lpDevmode = pData->printEnv.lpDevmode;
  1187. if (lpDevmode!= (LPDEVMODE) NULL ) {
  1188. //
  1189. // We have a devmode so look at it
  1190. //
  1191. if ( lpDevmode->dmFields & DM_PAPERSIZE) {
  1192. ppsCurPage->dmPaperSize = lpDevmode->dmPaperSize;
  1193. return(TRUE);
  1194. }
  1195. }
  1196. // True is returned in either case, since not having a devmode is
  1197. // not necessaraly a fatal error
  1198. //
  1199. return(TRUE);
  1200. }
  1201. /*** PsMakeDefaultDevmodeModsAndSetupResolution
  1202. *
  1203. *
  1204. * This function sets up our initial devmode and sets up some info
  1205. * so we can determine the scaling ratio based on the comparison
  1206. * of true device DPI, and internal interpreter DPI
  1207. *
  1208. * Entry:
  1209. * pData = Pointer to the current job structure
  1210. * pPsEvent = Pointer to the structure which contains the
  1211. * intrepreter session info.
  1212. *
  1213. * Returns:
  1214. * VOID
  1215. *
  1216. */
  1217. VOID
  1218. PsMakeDefaultDevmodeModsAndSetupResolution(
  1219. IN PPSEXEDATA pData,
  1220. IN OUT PPSDIBPARMS ppsDibParms )
  1221. {
  1222. HDC hIC;
  1223. LPDEVMODE lpDevmode;
  1224. BOOL bVerifyNewRes = FALSE;
  1225. lpDevmode = pData->printEnv.lpDevmode;
  1226. ppsDibParms->uiXDestRes = PSTODIB_X_DPI;
  1227. ppsDibParms->uiYDestRes = PSTODIB_Y_DPI;
  1228. // 1st thing to here is create an information context so we can
  1229. // determine the default resolution of the printer
  1230. hIC = CreateIC(TEXT(""),
  1231. (LPCTSTR) pData->pPrinterName,
  1232. TEXT(""),
  1233. lpDevmode );
  1234. if ( hIC != (HDC) NULL ) {
  1235. ppsDibParms->uiXDestRes = GetDeviceCaps(hIC, LOGPIXELSX);
  1236. ppsDibParms->uiYDestRes = GetDeviceCaps(hIC, LOGPIXELSY);
  1237. if (( GetDeviceCaps(hIC, LOGPIXELSX) > PSTODIB_X_DPI ) &&
  1238. ( GetDeviceCaps(hIC, LOGPIXELSY) > PSTODIB_Y_DPI ) &&
  1239. ( lpDevmode != (LPDEVMODE) NULL )) {
  1240. // Both resolutions are bigger lets go ahead and try to get the driver
  1241. // to go to PSTODIB_*_DPIS
  1242. //
  1243. lpDevmode->dmFields |= (DM_PRINTQUALITY | DM_YRESOLUTION);
  1244. lpDevmode->dmPrintQuality = PSTODIB_X_DPI;
  1245. lpDevmode->dmYResolution = PSTODIB_Y_DPI;
  1246. // Since we changed the resolution, it may not work so we need to
  1247. // reget the IC with the new devmode to see if it works.
  1248. bVerifyNewRes = TRUE;
  1249. }
  1250. DeleteDC( hIC );
  1251. if (bVerifyNewRes) {
  1252. hIC = CreateIC(TEXT(""),
  1253. (LPCTSTR) pData->pPrinterName,
  1254. TEXT(""),
  1255. lpDevmode);
  1256. if (hIC != (HDC) NULL) {
  1257. // Set the resolution for the job to the new value...
  1258. // we dont expect this to change for the duration ofthe
  1259. // job
  1260. ppsDibParms->uiXDestRes = GetDeviceCaps(hIC, LOGPIXELSX);
  1261. ppsDibParms->uiYDestRes = GetDeviceCaps(hIC, LOGPIXELSY);
  1262. DeleteDC(hIC);
  1263. }
  1264. }
  1265. }
  1266. if (lpDevmode != (LPDEVMODE)NULL) {
  1267. lpDevmode->dmFields |= (DM_ORIENTATION | DM_PAPERSIZE);
  1268. lpDevmode->dmOrientation = DMORIENT_PORTRAIT;
  1269. lpDevmode->dmCopies = 1;
  1270. }
  1271. }
  1272. /*** PsInitPrintEnv
  1273. *
  1274. *
  1275. * Initializes the data that tracks the DEVMODE for the current job
  1276. *
  1277. * Entry:
  1278. * pData = Pointer to the current job structure
  1279. * lpDevmode = Pointer to the current devmode to use for the job
  1280. *
  1281. * Returns:
  1282. * VOID
  1283. *
  1284. */
  1285. VOID PsInitPrintEnv( PPSEXEDATA pData, LPDEVMODE lpDevmode )
  1286. {
  1287. DWORD dwTotDevMode;
  1288. //
  1289. // Set the inital state of our flags
  1290. //
  1291. pData->printEnv.dwFlags = 0;
  1292. pData->printEnv.lpDevmode = (LPDEVMODE) NULL;
  1293. if (lpDevmode != (LPDEVMODE) NULL) {
  1294. //
  1295. // Since there is a devmode make a local copy cause we might
  1296. // be changing it.
  1297. //
  1298. dwTotDevMode = lpDevmode->dmSize + lpDevmode->dmDriverExtra;
  1299. pData->printEnv.lpDevmode = (LPDEVMODE) LocalAlloc( NONZEROLPTR,
  1300. dwTotDevMode );
  1301. if (pData->printEnv.lpDevmode != (LPDEVMODE) NULL) {
  1302. //
  1303. // Set the flag so we know to free this later
  1304. //
  1305. pData->printEnv.dwFlags |= PS_PRINT_FREE_DEVMODE;
  1306. //
  1307. // Now go and copy it
  1308. //
  1309. memcpy( (PVOID) pData->printEnv.lpDevmode,
  1310. (PVOID) lpDevmode,
  1311. dwTotDevMode );
  1312. }
  1313. }
  1314. }
  1315. /*** PsHandleBinaryFileLogicAndReturnBinaryStatus
  1316. *
  1317. *
  1318. * This routine will look at the begining buffer of data from the ps job
  1319. * and determine whether the job is BINARY. This is done by looking at the
  1320. * beg of the job and looking for a string the mac Spooler inserts. If
  1321. * this string exists it is converted to spaces and not passed through to the
  1322. * interpreter. At this point it is a BINARY job.
  1323. *
  1324. * Entry:
  1325. * pData = Pointer to the current job structure
  1326. *
  1327. * Returns:
  1328. * TRUE/FALSE = True means this job should be treated as BINARY.
  1329. *
  1330. *
  1331. */
  1332. BOOL PsHandleBinaryFileLogicAndReturnBinaryStatus( PPSEXEDATA pData )
  1333. {
  1334. DWORD dwIndex;
  1335. BOOL bRetVal = FALSE;
  1336. pData->lpBinaryPosToReadFrom = &pData->BinaryBuff[0];
  1337. pData->cbBinaryBuff = 0;
  1338. if( !ReadPrinter( pData->hPrinter,
  1339. pData->lpBinaryPosToReadFrom,
  1340. sizeof(pData->BinaryBuff),
  1341. &(pData->cbBinaryBuff) )) {
  1342. if (GetLastError() != ERROR_PRINT_CANCELLED) {
  1343. //
  1344. // Something happened... log it
  1345. //
  1346. PsLogEventAndIncludeLastError(EVENT_PSTODIB_GET_DATA_FAILED,TRUE);
  1347. #ifdef MYPSDEBUG
  1348. printf("\nSFMPsexe: Error from ReadPrinter when trying to get Binary buffer data ");
  1349. #endif
  1350. }
  1351. } else {
  1352. // Now do the compare
  1353. if (IsJobFromMac(pData))
  1354. {
  1355. bRetVal = TRUE;
  1356. }
  1357. //
  1358. // we retain this code just in case the job from an older SFM spooler
  1359. // that still prepends those strings
  1360. //
  1361. else if (!strncmp(pData->BinaryBuff, FILTERCONTROL, SIZE_FC) ||
  1362. !strncmp(pData->BinaryBuff, FILTERCONTROL_OLD, SIZE_FCOLD))
  1363. {
  1364. //
  1365. // turn filtering off & clear filter message
  1366. //
  1367. for (dwIndex = 0; dwIndex < SIZE_FC; dwIndex++) {
  1368. pData->BinaryBuff[dwIndex] = '\n' ;
  1369. }
  1370. bRetVal = TRUE;
  1371. }
  1372. }
  1373. return(bRetVal);
  1374. }
  1375. /*** PsPrintAbortProc
  1376. *
  1377. *
  1378. * The abort procedure the system occasiaonly calls to see if we should abort
  1379. * the current job
  1380. *
  1381. * Entry:
  1382. * hdc = The current device context were drawing into
  1383. * iError = A spooler error, we dont need to worry about this
  1384. *
  1385. * Returns:
  1386. * TRUE The job should continue to be processed
  1387. * FALSE The job should be aborted
  1388. *
  1389. *
  1390. */
  1391. BOOL CALLBACK PsPrintAbortProc( HDC hdc, int iError )
  1392. {
  1393. // If the print processor set the shared memory abort the job flag,
  1394. // then kill the job
  1395. //
  1396. if( *(Data.pdwFlags) & PS_SHAREDMEM_ABORTED ) {
  1397. return( FALSE );
  1398. }
  1399. return(TRUE);
  1400. }
  1401. /*** main
  1402. *
  1403. *
  1404. * This is the main entry point for the application and only interface to
  1405. * pstodib
  1406. *
  1407. *
  1408. * Entry:
  1409. * argc = Count of arguments
  1410. * argv = ptr to array of ptrs to each argument on the command
  1411. * line.
  1412. *
  1413. * Returns:
  1414. * 0 = OK, job finished via normal processing
  1415. * 99 = error of some sort
  1416. */
  1417. int __cdecl
  1418. main(
  1419. IN int argc,
  1420. IN TCHAR *argv[] )
  1421. {
  1422. PPSEXEDATA pData=&Data;
  1423. PSDIBPARMS psDibParms;
  1424. BOOL bRetVal = FALSE;
  1425. LPTSTR lpCommandLine;
  1426. // Get to the first item, which is the name of the shared memory that
  1427. // has all the info we need.
  1428. //
  1429. lpCommandLine = GetCommandLine();
  1430. while (*lpCommandLine && *lpCommandLine != ' ') {
  1431. lpCommandLine++;
  1432. }
  1433. while (*lpCommandLine && *lpCommandLine == ' ') {
  1434. lpCommandLine++;
  1435. }
  1436. // First clear out our structure
  1437. memset( (PVOID) pData, 0, sizeof(*pData));
  1438. // Set up our local structure
  1439. //
  1440. pData->signature = PSEXE_SIGNATURE;
  1441. // First thing to do is get the name of the object we will use for
  1442. // getting at the memory
  1443. if (lstrlen(lpCommandLine) == 0) {
  1444. // This is an error condition
  1445. PsCleanUpAndExitProcess(pData, TRUE);
  1446. }
  1447. pData->hShared = OpenFileMapping( FILE_MAP_READ, FALSE, lpCommandLine);
  1448. if (pData->hShared == (HANDLE) NULL ) {
  1449. PsLogEventAndIncludeLastError(EVENT_PSTODIB_INIT_FAILED,TRUE);
  1450. PsCleanUpAndExitProcess( pData, TRUE );
  1451. } else{
  1452. pData->pShared = (PPSPRINT_SHARED_MEMORY) MapViewOfFile( pData->hShared,
  1453. FILE_MAP_READ,
  1454. 0,
  1455. 0,
  1456. 0 );
  1457. if (pData->pShared == (PPSPRINT_SHARED_MEMORY) NULL) {
  1458. PsLogEventAndIncludeLastError(EVENT_PSTODIB_INIT_FAILED,TRUE);
  1459. PsCleanUpAndExitProcess( pData, TRUE );
  1460. }
  1461. // Now set up the data from the shared memory region
  1462. pData->pDocument = (LPTSTR) UTLPSRETURNPTRFROMITEM(pData->pShared,
  1463. pData->pShared->dwDocumentName);
  1464. pData->pPrinterName = (LPTSTR) UTLPSRETURNPTRFROMITEM(pData->pShared,
  1465. pData->pShared->dwPrinterName);
  1466. PsInitPrintEnv( pData, (LPDEVMODE) UTLPSRETURNPTRFROMITEM( pData->pShared,
  1467. pData->pShared->dwDevmode));
  1468. pData->pDocumentPrintDocName = (LPTSTR)
  1469. UTLPSRETURNPTRFROMITEM( pData->pShared,
  1470. pData->pShared->dwPrintDocumentDocName);
  1471. pData->semPaused = OpenEvent( EVENT_ALL_ACCESS,
  1472. FALSE,
  1473. (LPWSTR) UTLPSRETURNPTRFROMITEM( pData->pShared,
  1474. pData->pShared->dwControlName));
  1475. if (pData->semPaused == (HANDLE) NULL) {
  1476. PsLogEventAndIncludeLastError(EVENT_PSTODIB_INIT_FAILED,TRUE);
  1477. PsCleanUpAndExitProcess( pData, TRUE );
  1478. }
  1479. pData->pdwFlags = (LPDWORD) &pData->pShared->dwFlags;
  1480. pData->JobId = pData->pShared->dwJobId;
  1481. //
  1482. // Now check our Abort immediately flag. If its set GET OUT!
  1483. // This flag means that the print processor was not able to
  1484. // correclty set the AccessToken of the primage thread of this
  1485. // process to imporsonate the user which submitted the print job.
  1486. // because of this we immediately exit.
  1487. //
  1488. if (*(pData->pdwFlags) & PS_SHAREDMEM_SECURITY_ABORT ) {
  1489. #ifdef MYPSDEBUG
  1490. printf("\nSFMPSEXE: Aborting due to security violation request from sfmpsprt");
  1491. #endif
  1492. PsCleanUpAndExitProcess(pData,TRUE);
  1493. }
  1494. if (!OpenPrinter(pData->pDocumentPrintDocName,
  1495. &pData->hPrinter,
  1496. (LPPRINTER_DEFAULTS) NULL)) {
  1497. PsLogEventAndIncludeLastError(EVENT_PSTODIB_INIT_FAILED,TRUE);
  1498. PsCleanUpAndExitProcess(pData,TRUE);
  1499. }
  1500. // if there was no devmode get the default one...
  1501. if ( pData->printEnv.lpDevmode == (LPDEVMODE) NULL) {
  1502. PsGetDefaultDevmode( pData );
  1503. }
  1504. PsMakeDefaultDevmodeModsAndSetupResolution( pData, &psDibParms );
  1505. // Now build up the structure for Starting PStoDIB
  1506. psDibParms.uiOpFlags = 0; //Clear out to begin with..
  1507. psDibParms.fpEventProc = PsPrintCallBack;
  1508. psDibParms.hPrivateData = (HANDLE) pData;
  1509. //
  1510. // Now before we kick off the interpreter lets read in the beg of the job
  1511. // and decide if the data is to be interpreted binary.
  1512. //
  1513. if(PsHandleBinaryFileLogicAndReturnBinaryStatus( pData )) {
  1514. //
  1515. // Its a binary job so set the flag telling the interpreter such
  1516. //
  1517. psDibParms.uiOpFlags |= PSTODIBFLAGS_INTERPRET_BINARY;
  1518. #ifdef MYPSDEBUG
  1519. printf("\nSFMPSEXE:Binary requested");
  1520. #endif
  1521. }
  1522. bRetVal = !PStoDIB(&psDibParms);
  1523. }
  1524. //
  1525. // This function will clean up and call ExitProcess()
  1526. // thus we will NEVER get past this code
  1527. //
  1528. PsCleanUpAndExitProcess( pData, bRetVal);
  1529. // keep the compiler happy...
  1530. //
  1531. return(0);
  1532. }
  1533. /*** PsCleanUpAndExitProcess
  1534. *
  1535. * This function cleans up any resources allocated, then calls ExitProcess
  1536. * to terminate.
  1537. *
  1538. *
  1539. * Entry:
  1540. * pData = Pointer to current job structure
  1541. * bAbort = if true we are aborting.
  1542. *
  1543. * Returns:
  1544. * Never returns ANYTHING process actually ends HERE!
  1545. */
  1546. VOID
  1547. PsCleanUpAndExitProcess(
  1548. IN PPSEXEDATA pData,
  1549. IN BOOL bAbort )
  1550. {
  1551. // First clean up the DC, if we had one...
  1552. //
  1553. if (pData->hDC != (HDC) NULL) {
  1554. if (bAbort) {
  1555. AbortDoc( pData->hDC );
  1556. } else {
  1557. EndDoc( pData->hDC );
  1558. }
  1559. DeleteDC( pData->hDC);
  1560. }
  1561. //
  1562. // Now reset the error flag to error if we never did the startdoc
  1563. // this will force the spooler to remove the job.
  1564. //
  1565. if ( !(pData->printEnv.dwFlags & PS_PRINT_STARTDOC_INITIATED ) ){
  1566. bAbort = TRUE;
  1567. }
  1568. // Clean up the devmode if we allocated it
  1569. if (pData->printEnv.dwFlags & PS_PRINT_FREE_DEVMODE) {
  1570. LocalFree( (HLOCAL) pData->printEnv.lpDevmode);
  1571. }
  1572. // Clean up the printer handle
  1573. //
  1574. if (pData->hPrinter != (HANDLE) NULL) {
  1575. ClosePrinter( pData->hPrinter);
  1576. }
  1577. // Close the semaphore event
  1578. if (pData->semPaused != (HANDLE) NULL) {
  1579. CloseHandle( pData->semPaused);
  1580. }
  1581. if (pData->pShared != (LPVOID) NULL) {
  1582. UnmapViewOfFile( (LPVOID) pData->pShared);
  1583. }
  1584. if (pData->hShared != (HANDLE) NULL) {
  1585. CloseHandle( pData->hShared);
  1586. }
  1587. ExitProcess(bAbort ? PSEXE_ERROR_EXIT:PSEXE_OK_EXIT);
  1588. }
  1589. BOOL
  1590. IsJobFromMac(
  1591. IN PPSEXEDATA pData
  1592. )
  1593. {
  1594. PJOB_INFO_2 pji2GetJob=NULL;
  1595. DWORD dwNeeded;
  1596. DWORD dwRetCode;
  1597. BOOL fJobCameFromMac;
  1598. fJobCameFromMac = FALSE;
  1599. //
  1600. // get pParameters field of the jobinfo to see if this job came from a Mac
  1601. //
  1602. dwNeeded = 2000;
  1603. while (1)
  1604. {
  1605. pji2GetJob = LocalAlloc( LMEM_FIXED, dwNeeded );
  1606. if (pji2GetJob == NULL)
  1607. {
  1608. dwRetCode = GetLastError();
  1609. break;
  1610. }
  1611. dwRetCode = 0;
  1612. if (!GetJob( pData->hPrinter,pData->JobId, 2,
  1613. (LPBYTE)pji2GetJob, dwNeeded, &dwNeeded ))
  1614. {
  1615. dwRetCode = GetLastError();
  1616. }
  1617. if ( dwRetCode == ERROR_INSUFFICIENT_BUFFER )
  1618. {
  1619. LocalFree(pji2GetJob);
  1620. }
  1621. else
  1622. {
  1623. break;
  1624. }
  1625. }
  1626. if (dwRetCode == 0)
  1627. {
  1628. //
  1629. // if there is pParameter field present, and if it matches with our string,
  1630. // then the job came from a Mac
  1631. //
  1632. if (pji2GetJob->pParameters)
  1633. {
  1634. if ( (wcslen(pji2GetJob->pParameters) == LSIZE_FC) &&
  1635. (_wcsicmp(pji2GetJob->pParameters, LFILTERCONTROL) == 0) )
  1636. {
  1637. fJobCameFromMac = TRUE;
  1638. }
  1639. }
  1640. }
  1641. if (pji2GetJob)
  1642. {
  1643. LocalFree(pji2GetJob);
  1644. }
  1645. return(fJobCameFromMac);
  1646. }