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.

1004 lines
28 KiB

  1. /*
  2. Copyright (c) 1992,1993 Microsoft Corporation
  3. Module Name:
  4. psprint.c
  5. Abstract:
  6. This module contains the Print Processor code for the
  7. PStoDIB facility used to translate an incoming raw PostScript
  8. Level 1 data format to DIB's which can then be rendered on an
  9. output device.
  10. The print processor itself is defined as part of the WIN32 spool
  11. subsystem. A print processor dll is placed in a specific directory
  12. (based on the return of GetPrintProcessorDirectory(). The print
  13. processor is then added to the print subsystem by calling AddPrintProcessor()
  14. This is typically done by a setup program. The print subsystem only
  15. enumerates the print processors loaded at startup time. It does this
  16. by calling EnumPrintProcessorDataTypes() for each print processor registered
  17. with the spool subsystem. This information is kept and used to determine
  18. which PrintProcessor to use at print time based on the Datatype.
  19. This print processor exports the 4 required functions. They are:
  20. EnumPrintProcessorDatatypes
  21. OpenPrintProcessor
  22. PrintDocumentOnPrintProcessor
  23. ClosePrintProcessor
  24. ControlPrintProcessor
  25. The basic flow of a job from the spooler standpoint is as follows:
  26. At startup of system:
  27. Print subsystem enumerates all print processors registered in
  28. the system. For each print processor the datatypes are queried
  29. via EnumPrintProcessorDatatypes. This data is then stored
  30. as part of the print spooler information.
  31. A job is submitted via,
  32. OpenPrinter()
  33. StartDocPrinter() (Datatype = PSCRIPT1)
  34. WritePrinter()
  35. WritePrinter()
  36. ...
  37. ...
  38. EndDocPrinter()
  39. ClosePrinter()
  40. When it comes time to print our job the spooler calls:
  41. handle = OpenPrintProcessor(...)
  42. PrintDocumentOnPrintProcessor( handle , ... )
  43. ClosePrintProcessor( handle )
  44. Optionally:
  45. ControlPrintProcessor - For pausing jobs etc
  46. The basic flow of our print processor is as follows:
  47. EnumPrintProcessorDatatype
  48. This simply returns PSCRIPT1 as a unicode string, this
  49. is the ONLY datatype we support.
  50. OpenPrintProcessor
  51. Here we simply allocate some memory and record the data
  52. passed in to us which is required to succesfully print the
  53. postscript job
  54. PrintDocumentOnPrintProcessor
  55. This is the main worker routine. At this point all the relevant
  56. data for the job is copied into some named shared memory thats
  57. given a unique name based on our thread id. This name is then
  58. passed to the PSEXE process we start via the command line.
  59. PSEXE does all the interaction with PSTODIB when it completes
  60. then PrintDocumentOnPrintProcessor returns. A process is created
  61. because the ported trueimage interpreter was not re-entrant. Thus
  62. there is no way to have multiple threads of the same process using
  63. the interpreter simultaneously without the threads writing over
  64. the interpreters global variables.
  65. ClosePrintProcessor
  66. This code simply cleans up any resources allocated and returns
  67. to the spooler
  68. ControlPrintProcessor
  69. This code controls pausing/un-pausing and aborting a job that
  70. is currently being interpreted. This is done my managing some bits
  71. stored in shared memory that is visible to the exe we started.
  72. Author:
  73. James Bratsanos <v-jimbr@microsoft.com or mcrafts!jamesb>
  74. Revision History:
  75. 15 Sep 1992 Initial Version
  76. 06 Dec 1992 Modified to kick off process instead of doing all work
  77. internally
  78. 18 Mar 1993 Corrected EnumPrintProcessorDataTypes to return correctly
  79. Notes: Tab stop: 4
  80. --*/
  81. #include <windows.h>
  82. #include <memory.h>
  83. #include <stdarg.h>
  84. #include <stdio.h>
  85. #include <winspool.h>
  86. #include <winsplp.h>
  87. #include "psshmem.h"
  88. #include "psprint.h"
  89. #include "psutl.h"
  90. #include <excpt.h>
  91. #include <string.h>
  92. #include "debug.h"
  93. #include "..\..\lib\psdiblib.h"
  94. /*** EnumPrintProcessorDatatypes
  95. *
  96. * Returns back the different PrintProcessor data types which we
  97. * support. Currently ONLY PSCRIPT1. If the caller passed in a buffer
  98. * that was too small then we returned the required size.
  99. *
  100. * Return Value:
  101. *
  102. * FALSE = Success
  103. * TRUE = Failure
  104. */
  105. BOOL
  106. EnumPrintProcessorDatatypes(
  107. IN LPTSTR pName,
  108. IN LPTSTR pPrintProcessorName,
  109. IN DWORD Level,
  110. OUT LPBYTE pDatatypes,
  111. IN DWORD cbBuf,
  112. OUT LPDWORD pcbNeeded,
  113. OUT LPDWORD pcReturned
  114. )
  115. {
  116. DATATYPES_INFO_1 *pInfo1 = (DATATYPES_INFO_1 *)pDatatypes;
  117. DWORD cbTotal=0;
  118. LPBYTE pEnd;
  119. *pcReturned = 0;
  120. // If the user passed in a NULL pointer there can be no lentgh
  121. // associated so zero out
  122. if ( pDatatypes == (LPBYTE) NULL ) {
  123. cbBuf = (DWORD) 0;
  124. }
  125. pEnd = (LPBYTE) ( (LPBYTE)pInfo1 + cbBuf);
  126. cbTotal += lstrlen(PSTODIB_DATATYPE) *sizeof(TCHAR) + sizeof(TCHAR) +
  127. sizeof(DATATYPES_INFO_1);
  128. *pcbNeeded = cbTotal;
  129. // If there is room in the buffer return the string
  130. if (cbTotal <= cbBuf) {
  131. pEnd -=(BYTE)( lstrlen(PSTODIB_DATATYPE) *sizeof(TCHAR) + sizeof(TCHAR));
  132. lstrcpy((LPTSTR) pEnd, PSTODIB_DATATYPE);
  133. pInfo1->pName = (LPTSTR) pEnd;
  134. (*pcReturned)++;
  135. } else{
  136. SetLastError(ERROR_INSUFFICIENT_BUFFER);
  137. return FALSE;
  138. }
  139. return( TRUE );
  140. }
  141. /*** OpenPrintProcessor
  142. *
  143. * Returns a HANDLE to an open print processor which is then used
  144. * to uniquely identify this print processor in future function calls
  145. * to PrintDocumentOnPrintProcessor, ClosePrintProcessor and
  146. * ControlPrintProcessor.
  147. *
  148. * Return Value:
  149. *
  150. * NULL = Failure
  151. * !NULL = Success
  152. */
  153. HANDLE
  154. OpenPrintProcessor(
  155. IN LPTSTR pPrinterName,
  156. IN PPRINTPROCESSOROPENDATA pPrintProcessorOpenData
  157. )
  158. {
  159. PPRINTPROCESSORDATA pData;
  160. HANDLE hHeap;
  161. DWORD uDatatype=0;
  162. HANDLE hPrinter=0;
  163. LPBYTE pEnd;
  164. LPBYTE pBuffer;
  165. HDC hDC;
  166. DWORD dwTotDevMode;
  167. // If for some reason the spool subsystem called us with a datatype other
  168. // than PSCRIPT1 then return back a NULL handle since we dont know
  169. // how to handle anything other than PSCRIPT1
  170. if (lstrcmp( PSTODIB_DATATYPE, pPrintProcessorOpenData->pDatatype) != 0 ) {
  171. SetLastError(ERROR_INVALID_DATATYPE);
  172. return( (HANDLE) NULL );
  173. }
  174. // Allocate some memory for our job instance data
  175. pData = (PPRINTPROCESSORDATA) LocalAlloc( LPTR, sizeof(PRINTPROCESSORDATA));
  176. if (pData == (PPRINTPROCESSORDATA) NULL) {
  177. PsLogEvent(EVENT_PSTODIB_MEM_ALLOC_FAILURE,
  178. 0,
  179. NULL,
  180. PSLOG_ERROR);
  181. DBGOUT((TEXT("Memory allocation for local job storage failed")));
  182. SetLastError( ERROR_NOT_ENOUGH_MEMORY);
  183. return((HANDLE)NULL);
  184. }
  185. pData->cb = sizeof(PRINTPROCESSORDATA);
  186. pData->signature = PRINTPROCESSORDATA_SIGNATURE;
  187. pData->JobId = pPrintProcessorOpenData->JobId;
  188. pData->pPrinterName = AllocStringAndCopy(pPrinterName);
  189. pData->pDatatype = AllocStringAndCopy( pPrintProcessorOpenData->pDatatype);
  190. pData->pDocument = AllocStringAndCopy( pPrintProcessorOpenData->pDocumentName);
  191. pData->pParameters = AllocStringAndCopy( pPrintProcessorOpenData->pParameters);
  192. // Now copy the devmode
  193. pData->pDevMode = NULL;
  194. if (pPrintProcessorOpenData->pDevMode != (LPDEVMODE) NULL) {
  195. dwTotDevMode = pPrintProcessorOpenData->pDevMode->dmSize +
  196. pPrintProcessorOpenData->pDevMode->dmDriverExtra;
  197. pData->pDevMode = (LPDEVMODE) LocalAlloc( NONZEROLPTR, dwTotDevMode );
  198. if (pData->pDevMode != NULL) {
  199. memcpy( (PVOID) pData->pDevMode,
  200. (PVOID) pPrintProcessorOpenData->pDevMode,
  201. dwTotDevMode );
  202. pData->dwTotDevmodeSize = dwTotDevMode;
  203. }
  204. }
  205. return( (HANDLE) pData );
  206. }
  207. /*** GenerateSharedMemoryInfo
  208. *
  209. *
  210. * This function copies all the relevant information into some shared
  211. * memory so we can pass the data to PSEXE.
  212. *
  213. * Entry:
  214. * pDAta: Pointer to our internal print processor data that holds all
  215. * required information for the current job we are processing
  216. *
  217. * lpPtr: Pointer to the base of our shared memory area
  218. *
  219. * Return Value:
  220. * None
  221. *
  222. */
  223. VOID
  224. GenerateSharedMemoryInfo(
  225. IN PPRINTPROCESSORDATA pData,
  226. IN LPVOID lpPtr
  227. )
  228. {
  229. PPSPRINT_SHARED_MEMORY pShared;
  230. pShared = lpPtr;
  231. // Record the starting position of our dynamic data, ie where strings
  232. // of variable length and the raw devmode bytes are stored.
  233. //
  234. pShared->dwNextOffset = sizeof(*pShared);
  235. // Record the size for future reference, ie if something gets added etc
  236. // this serves as a version number of sorts;
  237. //
  238. pShared->dwSize = sizeof(*pShared);
  239. pShared->dwFlags = 0;
  240. // Move the job id over
  241. pShared->dwJobId = pData->JobId;
  242. UTLPSCOPYTOSHARED( pShared,
  243. pData->pPrinterName,
  244. pShared->dwPrinterName,
  245. (lstrlen(pData->pPrinterName) + 1 ) * sizeof(WCHAR) );
  246. UTLPSCOPYTOSHARED( pShared,
  247. pData->pDocument,
  248. pShared->dwDocumentName,
  249. (lstrlen(pData->pDocument) + 1 ) * sizeof(WCHAR));
  250. UTLPSCOPYTOSHARED( pShared,
  251. pData->pPrintDocumentDocName,
  252. pShared->dwPrintDocumentDocName,
  253. (lstrlen(pData->pPrintDocumentDocName) + 1) * sizeof(WCHAR));
  254. UTLPSCOPYTOSHARED( pShared,
  255. pData->pDevMode,
  256. pShared->dwDevmode,
  257. pData->pDevMode->dmSize + pData->pDevMode->dmDriverExtra);
  258. UTLPSCOPYTOSHARED( pShared,
  259. pData->pControlName,
  260. pShared->dwControlName,
  261. (lstrlen(pData->pControlName) + 1) * sizeof(WCHAR));
  262. }
  263. /*** PrintDocumentOnPrintProcessor
  264. *
  265. * This function gathers all required data needed to interpret/print a
  266. * PostScript job, puts it in a shared memory area and kicks off a process
  267. * called psexe to actually interpret/print the job. When PSEXE finally
  268. * terminates this function returns.
  269. *
  270. * Starting a seperate process is done because the PSTODIB code is NOT
  271. * re-entrant and thus requires a seperate data segment (for all its globals)
  272. * for each seperate job were interpreting. Since the spooler is ONE exe
  273. * with multiple threads all threads share the same data segment and thus
  274. * dont provide the functionality we need to implement pstodib. Starting
  275. * a seperate process guarantees a new DATA segment for all globals used
  276. * in the PSTODIB component.
  277. *
  278. *
  279. * Entry:
  280. * hPrintProcessor: The handle we gave the print spooler via
  281. * OpenPrintProcessor.
  282. *
  283. * pDocumentName: The document /printer to read from so we can retrieve
  284. * the data for the current PostScript job we are to
  285. * interpret.
  286. *
  287. * Return Value:
  288. *
  289. * TRUE = Success
  290. * FALSE = Failure
  291. */
  292. BOOL
  293. PrintDocumentOnPrintProcessor(
  294. HANDLE hPrintProcessor,
  295. LPTSTR pDocumentName
  296. )
  297. {
  298. PPRINTPROCESSORDATA pData;
  299. DOC_INFO_1 DocInfo;
  300. DWORD rc;
  301. DWORD NoRead, NoWritten;
  302. HANDLE hPrinter;
  303. DOCINFO docInfo;
  304. TCHAR szNameOfRegion[100];
  305. TCHAR szBuff[100];
  306. STARTUPINFO startUpInfo;
  307. PROCESS_INFORMATION processInfo;
  308. TCHAR szCmdLine[500];
  309. WCHAR szwControlEventName[33];
  310. DWORD dwProcessExitCode;
  311. DWORD dwProcessPriorityClass;
  312. DWORD dwThreadPriority;
  313. DWORD dwSizeOfSharedMemory = 0;
  314. LPVOID lpBase;
  315. if (!(pData = ValidateHandle(hPrintProcessor))) {
  316. SetLastError(ERROR_INVALID_HANDLE);
  317. DBGOUT((TEXT("handle validation failure, PrintDocumentOnPrintProcessor")));
  318. return FALSE;
  319. }
  320. // Store the document name so it can get copied into shared memory
  321. pData->pPrintDocumentDocName = AllocStringAndCopy(pDocumentName);
  322. wsprintf( szBuff, TEXT("%s%d"), PSTODIB_STRING, GetCurrentThreadId());
  323. lstrcpy( szwControlEventName, szBuff);
  324. lstrcat( szwControlEventName, PSTODIB_EVENT_STRING );
  325. pData->pControlName = AllocStringAndCopy(szwControlEventName);
  326. //
  327. // Create an event to manage pausing/unpausing the print processor
  328. //
  329. pData->semPaused = CreateEvent(NULL, TRUE, TRUE,szwControlEventName);
  330. dwSizeOfSharedMemory = sizeof(PSPRINT_SHARED_MEMORY);
  331. dwSizeOfSharedMemory += ((((pData->pPrinterName?lstrlen(pData->pPrinterName):0) + 1 ) * sizeof(WCHAR))+3) & ~0x03;
  332. dwSizeOfSharedMemory += ((((pData->pDocument?lstrlen(pData->pDocument):0) + 1 ) * sizeof(WCHAR))+3) & ~0x03;
  333. dwSizeOfSharedMemory += ((((pData->pPrintDocumentDocName?lstrlen(pData->pPrintDocumentDocName):0) + 1) * sizeof(WCHAR))+3) & ~0x03;
  334. dwSizeOfSharedMemory += (((pData->pDevMode?pData->pDevMode->dmSize:0) + (pData->pDevMode?pData->pDevMode->dmDriverExtra:0))+3) & ~0x03;
  335. dwSizeOfSharedMemory += ((((pData->pControlName?lstrlen(pData->pControlName):0) + 1) * sizeof(WCHAR))+3) & ~0x03;
  336. // Create a shared memory area that we can write to....
  337. pData->hShared = CreateFileMapping( INVALID_HANDLE_VALUE, // out of paging file
  338. NULL,
  339. PAGE_READWRITE,
  340. 0,
  341. dwSizeOfSharedMemory,
  342. szBuff );
  343. if (pData->hShared == (HANDLE) NULL) {
  344. //
  345. // Last error should already be set by CreateFileMapping
  346. //
  347. DBGOUT((TEXT("CreateFileMapping failure in psprint")));
  348. return(FALSE);
  349. }
  350. lpBase = (PPSPRINT_SHARED_MEMORY) MapViewOfFile( pData->hShared,
  351. FILE_MAP_WRITE,
  352. 0,
  353. 0,
  354. dwSizeOfSharedMemory);
  355. if (lpBase == (PPSPRINT_SHARED_MEMORY) NULL) {
  356. //
  357. // Last error should already be set by CreateFileMapping
  358. //
  359. DBGOUT((TEXT("MapViewOfFile failure in psprint")));
  360. return(FALSE);
  361. }
  362. // Put all required information into the shared memory area we created
  363. GenerateSharedMemoryInfo( pData, lpBase );
  364. // Now mark the fact that the shared memory stuff exists
  365. pData->pShared = (PPSPRINT_SHARED_MEMORY) lpBase;
  366. pData->fsStatus |= PRINTPROCESSOR_SHMEM_DEF;
  367. // Generate the string to pass to CreateProcess in order to start up
  368. // PSEXE.
  369. //
  370. // NOTE: A interesting way to debug psexe is to simply start windbg
  371. // first passing in psexe and the normal command line. I found
  372. // this VERY useful during debuging.
  373. //
  374. //wsprintf( szCmdLine, TEXT("windbg %s %s"), PSEXE_STRING, szBuff);
  375. wsprintf( szCmdLine, TEXT("%s %s"), PSEXE_STRING, szBuff);
  376. // Define a STARTUPINFO structure required for CreateProcess. Since
  377. // the new process runs DETACHED and has no console, most of the data is
  378. // default or none.
  379. startUpInfo.cb = sizeof(STARTUPINFO);
  380. startUpInfo.lpReserved = NULL;
  381. startUpInfo.lpDesktop = NULL;
  382. startUpInfo.lpTitle = NULL;
  383. startUpInfo.dwFlags = 0;
  384. startUpInfo.cbReserved2 = 0;
  385. startUpInfo.lpReserved2 = NULL;
  386. // ***** IMPORTANT *****
  387. // Create the process to actually interpret and print the specified
  388. // PostScript job. We create this process suspended, because of the
  389. // way the NT security system works. When CreateProcess is called we
  390. // end up giving the security access token of the spooler process to
  391. // PSEXE, this is incorrect since we want to give PSEXE the security
  392. // access token of the current thread. Since the job needs to access
  393. // resources which the spooler (running in the system context) may not
  394. // have access to but the client (whoever submitted the job) does. To
  395. // do this we need to set the access token of the primary thread of
  396. // PSEXE to whatever access token the current thread has. The way
  397. // this works is to create the process SUSPENDED then set the security
  398. // access token of the primary thread of PSEXE, then Resume the
  399. // thread to let it process our job. We sit blocked on WaitForSingleObject
  400. // until the job completes.
  401. //
  402. //
  403. if(!CreateProcess(NULL,
  404. szCmdLine,
  405. NULL,
  406. NULL,
  407. FALSE,
  408. #ifdef PSCHECKED
  409. CREATE_SUSPENDED | CREATE_NEW_CONSOLE, //DEBUG
  410. #else
  411. CREATE_SUSPENDED | DETACHED_PROCESS,
  412. #endif
  413. NULL,
  414. NULL,
  415. &startUpInfo,
  416. &processInfo ) ) {
  417. //
  418. // Last error should already be set by CreateProcess
  419. //
  420. PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_STARTPSEXE_FAILED,
  421. TRUE );
  422. DBGOUT((TEXT("Create Process failed")));
  423. return(FALSE);
  424. }
  425. #ifdef OLD_PRIORITY
  426. if (!SetPriorityClass(processInfo.hProcess, IDLE_PRIORITY_CLASS)){
  427. DBGOUT((TEXT("Failed trying to reset the priority class")));
  428. }
  429. #endif
  430. // Just to make sure the thread priority of our new thread matches,
  431. // the spooler and the Priority class of our exe matches the spooler
  432. //
  433. if( (dwProcessPriorityClass = GetPriorityClass( GetCurrentProcess())) != 0 ) {
  434. if (!SetPriorityClass( processInfo.hProcess, dwProcessPriorityClass)) {
  435. PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
  436. FALSE );
  437. DBGOUT((TEXT("Failed trying to reset priority class for smfpsexe")));
  438. }
  439. } else {
  440. PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
  441. FALSE );
  442. DBGOUT((TEXT("Cannot retrieve current priority class!")));
  443. }
  444. //
  445. // Grab the current threads priority
  446. //
  447. if ((dwThreadPriority = GetThreadPriority( GetCurrentThread())) !=
  448. THREAD_PRIORITY_ERROR_RETURN ) {
  449. // It worked so set the thread priority
  450. if (!SetThreadPriority( processInfo.hThread, dwThreadPriority)) {
  451. PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
  452. FALSE );
  453. DBGOUT((TEXT("Setting thread priority failed for sfmpsexe")));
  454. }
  455. } else {
  456. PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SETPRIORITY_FAILED,
  457. FALSE );
  458. DBGOUT((TEXT("Cannot retrieve thread priority, sfmpsprt.dll")));
  459. }
  460. // Why the #if 0 below....
  461. // NT-Spooler always runs under LocalSystem. If macprint also runs as LocalSystem,
  462. // then setting security token is a no-op. If macprint runs in some user's account then
  463. // we run into the following problem: user32.dll fails to initialize because this new
  464. // process running under user's context tries to access winsta0 and fails because it's got
  465. // no privileges (only LocalSystem, not even admins get this priv). If we don't put this
  466. // user's token, we don't lose anything except one case: if the port is configured to go to
  467. // a unc name (e.g. \\foobar\share) where LocalSystem won't have priv, but the user will.
  468. // But this case is a generic problem in NT-Spooler, so it's an ok compromise
  469. //
  470. // p.s. another solution considered: create this process with a different winsta (pass an
  471. // empty string for lpDesktop parm above, instead of NULL). This works ok except if there
  472. // is any dialog generated - the dialog shows up in the process's winsta, not on the desktop
  473. // which causes the job to "hang" waiting for input! A common case of a dialog appearing is
  474. // if the port configured is FILE.
  475. #if 0
  476. // Set the security access token of the primary thread of PSEXE, the
  477. // reason for that the spooler is imporsonating the client which
  478. // submitted the job when we get here. Since we are kicking off another
  479. // process to do the real work for us, this new process primary thread
  480. // must have the same privelege as the current thread (namely the client
  481. // which submitted the job). This relies on the fact the Spooler is
  482. // imporsonating and thus we will fail the job if the access token
  483. // transfer fails.
  484. //
  485. if ( !PsUtlSetThreadToken( processInfo.hThread )) {
  486. /*
  487. * PsPrintLogEventAndIncludeLastError( EVENT_PSTODIB_SECURITY_PROBLEM,
  488. * TRUE );
  489. */
  490. DBGOUT((TEXT("Failed trying to reset the thread token")));
  491. //
  492. // The code that sets the abort flag used to force the job
  493. // to abort. Since this behaviour does not mimick the spooler
  494. // we will take it out. This always caused any pstodib jobs
  495. // which hung around past a reboot to fail.
  496. //
  497. // JSB 6-25-93
  498. //
  499. //pData->pShared->dwFlags |= PS_SHAREDMEM_SECURITY_ABORT;
  500. }
  501. #endif
  502. //
  503. // Now that we have/have not set the thread security access token for PSEXE
  504. // let it run its course
  505. //
  506. ResumeThread( processInfo.hThread);
  507. //
  508. // Now wait for the Interpreter to complete for any reason since
  509. // the spool subsystem does not expect us to return from
  510. // PrintDocumentOnPrintProcessor until the job is complete
  511. //
  512. WaitForSingleObject( processInfo.hProcess, INFINITE);
  513. // Get the termination reason
  514. GetExitCodeProcess( processInfo.hProcess, &dwProcessExitCode);
  515. // Close the handles which are not required any more
  516. //
  517. CloseHandle( processInfo.hProcess );
  518. CloseHandle( processInfo.hThread );
  519. // Clean up resources used by shared memory
  520. //
  521. return( (dwProcessExitCode == 0) ? TRUE : FALSE );
  522. }
  523. /*** PsLocalFree
  524. *
  525. * This function simply verifies the handle is not null and calls localfree
  526. *
  527. * Entry:
  528. * lpPtr: The pointer to free if not null
  529. *
  530. * Exit:
  531. * none;
  532. *
  533. */
  534. VOID PsLocalFree( IN LPVOID lpPtr )
  535. {
  536. if (lpPtr != (LPVOID) NULL) {
  537. LocalFree( (HLOCAL) lpPtr);
  538. }
  539. }
  540. /*** ClosePrintProcessor
  541. *
  542. * This functions simply cleans up any resources we used during our
  543. * job and returs:
  544. *
  545. * Entry:
  546. * hPrintProcessor: The handle we returned to the spooler in the
  547. * OpenPrintProcessor call.
  548. *
  549. * Exit:
  550. * True = Success
  551. * False = failure;
  552. *
  553. */
  554. BOOL
  555. ClosePrintProcessor(
  556. IN HANDLE hPrintProcessor
  557. )
  558. {
  559. PPRINTPROCESSORDATA pData;
  560. HANDLE hHeap;
  561. pData = ValidateHandle(hPrintProcessor);
  562. if (!pData) {
  563. SetLastError(ERROR_INVALID_HANDLE);
  564. DBGOUT((TEXT("Invalid handle to closeprintprocessor, psprint")));
  565. return FALSE;
  566. }
  567. pData->fsStatus &= ~PRINTPROCESSOR_SHMEM_DEF;
  568. if (pData->pShared != (PPSPRINT_SHARED_MEMORY) NULL) {
  569. UnmapViewOfFile( (LPVOID) pData->pShared );
  570. }
  571. if (pData->hShared != (HANDLE) NULL) {
  572. CloseHandle( pData->hShared );
  573. }
  574. pData->signature = 0;
  575. /* Release any allocated resources */
  576. if( pData->semPaused != (HANDLE) NULL ) {
  577. CloseHandle(pData->semPaused);
  578. }
  579. PsLocalFree( (LPVOID) pData->pPrinterName);
  580. PsLocalFree( (LPVOID) pData->pDatatype );
  581. PsLocalFree( (LPVOID) pData->pDocument );
  582. PsLocalFree( (LPVOID) pData->pParameters);
  583. PsLocalFree( (LPVOID) pData->pControlName);
  584. PsLocalFree( (LPVOID) pData->pDevMode );
  585. PsLocalFree( (LPVOID) pData->pPrintDocumentDocName );
  586. PsLocalFree( (LPVOID) pData );
  587. return TRUE;
  588. }
  589. /* ControlPrintProcessor
  590. *
  591. * This function controls pausing/unpausing of the print processor as well
  592. * aborting the current job, mainly this routine either sets/clears a named
  593. * event that the psexe program responds to, or sets a bit in some shared
  594. * memory to tell psexe to abort the current job
  595. *
  596. * Entry:
  597. * hPrintProcessor: The handle we returned to the spooler in the
  598. * OpenPrintProcessor call.
  599. *
  600. * Command: JOB_CONTROL_* (PAUSE,CANCEL,RESUME) as defined by
  601. * the Win32 print processor specification
  602. *
  603. * Exit:
  604. * TRUE: Request was satisfied
  605. * FALSE: Request was NOT satisfied
  606. *
  607. */
  608. BOOL
  609. ControlPrintProcessor(
  610. IN HANDLE hPrintProcessor,
  611. IN DWORD Command
  612. )
  613. {
  614. PPRINTPROCESSORDATA pData;
  615. if (pData = ValidateHandle(hPrintProcessor)) {
  616. switch (Command) {
  617. case JOB_CONTROL_PAUSE:
  618. ResetEvent(pData->semPaused);
  619. return(TRUE);
  620. break;
  621. case JOB_CONTROL_CANCEL:
  622. if (pData->fsStatus & PRINTPROCESSOR_SHMEM_DEF) {
  623. // shared memory is defined so update the bit in the shared
  624. // memory areay that signal aborting of the job
  625. // shared memory that define our state
  626. pData->pShared->dwFlags |= PS_SHAREDMEM_ABORTED;
  627. }
  628. /**** Intentional fall through to release job if paused */
  629. case JOB_CONTROL_RESUME:
  630. SetEvent(pData->semPaused);
  631. return(TRUE);
  632. break;
  633. default:
  634. return(FALSE);
  635. break;
  636. }
  637. } else {
  638. DBGOUT((TEXT("ControlPrintProcessor was passed an invalid handle, psprint")));
  639. }
  640. return( FALSE );
  641. }
  642. // NOT IMPLEMENTED BY SPOOLER YET, as of 3/14/93
  643. BOOL
  644. InstallPrintProcessor(
  645. HWND hWnd
  646. )
  647. {
  648. MessageBox(hWnd, TEXT("SfmPsPrint"), TEXT("Print Processor Setup"), MB_OK);
  649. return TRUE;
  650. }
  651. /* ValidateHandle
  652. *
  653. * Helper function which verifies the passed in handle is really a
  654. * handle to our own internal data structure
  655. *
  656. * Entry
  657. *
  658. * hQProc: Handle to our internal data structure
  659. *
  660. * Exit:
  661. *
  662. * NULL: Not a valid internal data structure
  663. * !NULL: A valid pointer to our internal data structure
  664. *
  665. */
  666. PPRINTPROCESSORDATA
  667. ValidateHandle(
  668. HANDLE hQProc
  669. )
  670. {
  671. PPRINTPROCESSORDATA pData = (PPRINTPROCESSORDATA)hQProc;
  672. if (pData && pData->signature == PRINTPROCESSORDATA_SIGNATURE)
  673. return( pData );
  674. else {
  675. return( NULL );
  676. }
  677. }
  678. #ifdef MYPSDEBUG
  679. /* DbgPsPrint
  680. *
  681. * Debuger message facility which also pops up a message box
  682. *
  683. * Entry:
  684. * wprintf style format/ var arg data
  685. *
  686. * Exit:
  687. * nothing (void function)
  688. *
  689. */
  690. VOID
  691. DbgPsPrint(
  692. PTCHAR ptchFormat, ...
  693. )
  694. {
  695. va_list marker;
  696. TCHAR buffer[512];
  697. va_start( marker, ptchFormat );
  698. wvsprintf( buffer, ptchFormat, marker );
  699. va_end( marker );
  700. OutputDebugString( buffer );
  701. MessageBox( (HWND) NULL, (LPTSTR) &buffer, TEXT("SFMPsPrint"), MB_OK);
  702. }
  703. #endif
  704. /* AllocStringAndCopy
  705. *
  706. * Helper function which allocates some memory and copies the source
  707. * string into it
  708. *
  709. * Entry:
  710. * lpSrc: Pointer to string to copy
  711. *
  712. * Exit:
  713. * NULL: Failure
  714. * !NULL: Pointer to newly allocated memory with string copied into it
  715. *
  716. */
  717. LPTSTR
  718. AllocStringAndCopy(
  719. LPTSTR lpSrc
  720. )
  721. {
  722. LPTSTR pRetString=(LPTSTR)NULL;
  723. // Allocate the memory for the string
  724. if (lpSrc) {
  725. pRetString = (LPTSTR) LocalAlloc(LPTR, (lstrlen(lpSrc) + 1) * sizeof(TCHAR));
  726. if (pRetString != (LPTSTR) NULL) {
  727. lstrcpy( pRetString, lpSrc );
  728. } else{
  729. PsLogEvent(EVENT_PSTODIB_MEM_ALLOC_FAILURE,
  730. 0,
  731. NULL,
  732. PSLOG_ERROR);
  733. }
  734. }
  735. return(pRetString);
  736. }
  737. VOID
  738. PsPrintLogEventAndIncludeLastError(
  739. IN DWORD dwErrorEvent,
  740. IN BOOL bError )
  741. {
  742. TCHAR atBuff[20];
  743. TCHAR *aStrs[2];
  744. wsprintf( atBuff,TEXT("%d"), GetLastError());
  745. aStrs[0] = atBuff;
  746. PsLogEvent( dwErrorEvent,
  747. 1,
  748. aStrs,
  749. PSLOG_ERROR );
  750. }