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.

644 lines
18 KiB

4 years ago
  1. /* ---File: printer.c -----------------------------------------------------
  2. *
  3. * Description:
  4. * Contains functions for managing network print queues.
  5. *
  6. * This document contains confidential/proprietary information.
  7. * Copyright (c) 1990-1992 Microsoft Corporation, All Rights Reserved.
  8. *
  9. * Revision History:
  10. * [00] 21-Nov-90 stevecat created
  11. * [01] 03-Jan-91 stevecat Modified to use Windows MDI
  12. * [02] 25-Mar-91 stevecat Modified to use NT WINSPOOL APIs
  13. * [03] 13-Jan-92 stevecat New PrintMan UI
  14. * [04] 01-Mar-92 davesn New APIs
  15. *
  16. * ---------------------------------------------------------------------- */
  17. /* Notes -
  18. Global Functions:
  19. AllocQueue () - Allocate memory for QUEUE struct and initialize it
  20. DeleteQJ () - Delete selected print job or all jobs on a queue
  21. DestroyPrinter () - Delete printer and memory associated with it
  22. FreeQueue () - Free local memory for QUEUE struct.
  23. GetJobs () - Retrieve info on print queues and theirjobs
  24. PauseResumeQJ () - Pause or Continue selected print job or queue
  25. Local Functions:
  26. */
  27. #include "printman.h"
  28. VOID FreeJobInfo( PQUEUE pQueue );
  29. /* --- Function: AllocQueue -------------------------------------------------
  30. *
  31. * AllocQueue (LPTSTR pPrinterName)
  32. *
  33. * Description:
  34. * Allocate local memory for QUEUE struct and initialize it.
  35. *
  36. * ---------------------------------------------------------------------- */
  37. PQUEUE
  38. AllocQueue(
  39. LPTSTR pPrinterName
  40. )
  41. {
  42. PQUEUE pQueue;
  43. if( ( pQueue = AllocSplMem( sizeof( QUEUE ) ) )
  44. &&( pQueue->pPrinterName = AllocSplStr( pPrinterName ) ) )
  45. {
  46. pQueue->pPrinter = NULL;
  47. pQueue->cbPrinterBuf = 0;
  48. pQueue->pJobs = NULL;
  49. pQueue->cJobs = 0;
  50. pQueue->cbJobsBuf = 0;
  51. }
  52. else
  53. if( pQueue )
  54. {
  55. FreeSplMem( pQueue );
  56. pQueue = NULL;
  57. }
  58. return pQueue;
  59. }
  60. /* --- Function: FreeQueue -------------------------------------------------
  61. *
  62. * FreeQueue(PQUEUE pQueue)
  63. *
  64. * Description:
  65. * Free local memory for QUEUE struct.
  66. *
  67. * ---------------------------------------------------------------------- */
  68. BOOL
  69. FreeQueue(
  70. PQUEUE pQueue
  71. )
  72. {
  73. if(pQueue->pServerName)
  74. FreeSplStr(pQueue->pServerName);
  75. FreeSplStr(pQueue->pPrinterName);
  76. FreeSplMem(pQueue);
  77. return TRUE;
  78. }
  79. /* --- Function: DeleteQJ ---------------------------------------------------
  80. *
  81. * DeleteQJ (PQUEUE pQueue)
  82. *
  83. * Description:
  84. * Delete selected print job or all jobs on print queue
  85. *
  86. * ---------------------------------------------------------------------- */
  87. DWORD DeleteQJ (HWND hwnd, PQUEUE pQueue)
  88. {
  89. DWORD Error = 0;
  90. if (!pQueue)
  91. return 0;
  92. if (pQueue->SelJobId)
  93. {
  94. // Cancel the print job
  95. if (!SetJob(pQueue->hPrinter,
  96. pQueue->SelJobId,
  97. 0, NULL,
  98. JOB_CONTROL_CANCEL))
  99. {
  100. Error = GetLastError();
  101. DBGMSG( DBG_WARNING, ("PrintManager.DeleteQJ::SetJob.Cancel failed %d.\n", Error) );
  102. }
  103. }
  104. else
  105. {
  106. // Make sure user wants to delete ALL jobs before actually doing it,
  107. // if there's more than one job queued:
  108. if ( ( pQueue->cJobs == 1 )
  109. ||( Message( hwnd, MSG_CONFIRMATION, IDS_PRINTMANAGER,
  110. IDS_DELETEALLPRINTJOBS_S, pQueue->pPrinterName ) == IDOK ) )
  111. // Delete all jobs on printer
  112. if (!SetPrinter(pQueue->hPrinter, 0, NULL, PRINTER_CONTROL_PURGE))
  113. {
  114. Error = GetLastError();
  115. DBGMSG( DBG_WARNING, ("PrintManager.DeleteQJ::SetPrinter failed %d.\n", Error) );
  116. }
  117. }
  118. return Error;
  119. }
  120. /* --- Function: DestroyPrinter ---------------------------------------------
  121. *
  122. * DestroyPrinter(PQUEUE pQueue)
  123. *
  124. * Description:
  125. * Delete printer and free all memory for it.
  126. *
  127. * ---------------------------------------------------------------------- */
  128. BOOL
  129. DestroyPrinter(
  130. PQUEUE pQueue
  131. )
  132. {
  133. if (pQueue->pPrinter)
  134. FreeSplMem(pQueue->pPrinter);
  135. if( pQueue->pJobs )
  136. FreeSplMem(pQueue->pJobs);
  137. if( pQueue->cbSelJob > 0 )
  138. FreeSplMem(pQueue->pSelJob);
  139. FreeQueue(pQueue);
  140. return TRUE;
  141. }
  142. VOID
  143. DestroyServer(
  144. PSERVER_CONTEXT pServerContext
  145. )
  146. {
  147. FreeSplStr( pServerContext->pServerName );
  148. if (pServerContext->pPrinters )
  149. FreeSplMem( pServerContext->pPrinters );
  150. FreeSplMem( pServerContext );
  151. }
  152. VOID DestroyMDIWinInfo( PMDIWIN_INFO pInfo )
  153. {
  154. if( pInfo->WindowType == MDIWIN_SERVER )
  155. DestroyServer( pInfo->pContext );
  156. else
  157. DestroyPrinter( pInfo->pContext );
  158. CloseHandle( pInfo->DataMutex );
  159. CloseHandle( pInfo->RefreshSignal );
  160. FreeSplMem( pInfo->pColumns );
  161. FreeSplMem( pInfo );
  162. }
  163. int GetSelectedJobIndex( PQUEUE pQueue )
  164. {
  165. BOOL JobIdFound = FALSE;
  166. DWORD i;
  167. i = 0;
  168. while( !JobIdFound && ( i < pQueue->cEnumJobs ) )
  169. {
  170. if( pQueue->pJobs[i].JobId == pQueue->SelJobId )
  171. JobIdFound = TRUE;
  172. else
  173. i++;
  174. }
  175. return ( JobIdFound ? i : -1 );
  176. }
  177. LPJOB_INFO_2
  178. UpdateJobInfo(
  179. HANDLE hPrinter,
  180. DWORD JobId,
  181. LPJOB_INFO_2 pJob,
  182. PDWORD pcbBuf
  183. )
  184. {
  185. DWORD cbNeeded;
  186. DWORD Error;
  187. BOOL ForgetIt = FALSE;
  188. DBGMSG( DBG_TRACE, ( "UpdateJobInfo, JobId == %d\n", JobId ) );
  189. if( !GetJob( hPrinter, JobId, 2, (LPBYTE)pJob, *pcbBuf, &cbNeeded ) )
  190. {
  191. Error = GetLastError();
  192. if( Error == ERROR_INSUFFICIENT_BUFFER )
  193. {
  194. pJob = ReallocSplMem( pJob, cbNeeded );
  195. if( pJob )
  196. {
  197. if( !GetJob( hPrinter, JobId, 2, (LPBYTE)pJob, cbNeeded, &cbNeeded ) )
  198. ForgetIt = TRUE;
  199. }
  200. else
  201. ForgetIt = TRUE;
  202. }
  203. else
  204. ForgetIt = TRUE;
  205. if( ForgetIt )
  206. {
  207. if( pJob )
  208. FreeSplMem( pJob );
  209. pJob = NULL;
  210. *pcbBuf = 0;
  211. }
  212. }
  213. else
  214. *pcbBuf = cbNeeded;
  215. DBGMSG( DBG_TRACE, ( "UpdateJobInfo returned %08x\n", pJob ) );
  216. return pJob;
  217. }
  218. /* --- Function: GetJobs ----------------------------------------------------
  219. *
  220. * GetJobs (HWND hWnd, PQUEUE pQueue)
  221. *
  222. * Description:
  223. * Retrieve current Printer status and its Jobs from WINSPOOL API.
  224. *
  225. * ---------------------------------------------------------------------- */
  226. BOOL GetJobs( PVOID pContext, PDWORD pFlags )
  227. {
  228. LPPRINTER_INFO_2 pNewPrinter = NULL;
  229. DWORD cbNewPrinterBuf;
  230. PQUEUE pQueue;
  231. DWORD Error;
  232. DWORD cbNewJobsBuf;
  233. LPJOB_INFO_2 pNewJobs = NULL;
  234. DWORD cNewJobs;
  235. int SelectedJobIndex;
  236. DWORD TryEnumJobs;
  237. BOOL rc;
  238. pQueue = (PQUEUE)pContext;
  239. if( !pQueue )
  240. {
  241. DBGMSG( DBG_WARNING, ( "GetJobs called with pQueue == NULL\n" ) );
  242. return FALSE;
  243. }
  244. if( !pQueue->hPrinter )
  245. {
  246. LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
  247. DBGMSG( DBG_WARNING, ( "GetJobs called with hPrinter == NULL, re-opening!\n" ) );
  248. ReopenPrinter(pQueue, pQueue->pMDIWinInfo->WindowType, FALSE);
  249. ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
  250. }
  251. if (!pQueue->hPrinter)
  252. return FALSE;
  253. pQueue->Error = 0;
  254. if( *pFlags & PRINTER_CHANGE_PRINTER )
  255. {
  256. if( cbNewPrinterBuf = pQueue->cbPrinterBuf )
  257. pNewPrinter = AllocSplMem( cbNewPrinterBuf );
  258. DBG_IN_PROTECTED_DATA( pQueue->pMDIWinInfo );
  259. LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
  260. ENTER_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
  261. rc = GetGeneric( (PROC)GetPrinter, 2, (LPBYTE *)&pNewPrinter,
  262. cbNewPrinterBuf, &cbNewPrinterBuf,
  263. pQueue->hPrinter, NULL );
  264. LEAVE_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
  265. #if DBG
  266. if( rc && !pNewPrinter )
  267. {
  268. DBGMSG( DBG_ERROR, ( "GetGeneric( GetPrinter ) returned TRUE, but pNewBuffer is NULL.\n"
  269. "\tPrinter: %ls\n", pQueue->pPrinterName ) );
  270. }
  271. #endif /* DBG */
  272. ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
  273. if (!rc) {
  274. //
  275. // Attempt to reopen
  276. //
  277. if (pQueue->hPrinter) {
  278. ClosePrinter(pQueue->hPrinter);
  279. pQueue->hPrinter = NULL;
  280. }
  281. LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
  282. ReopenPrinter(pQueue,
  283. pQueue->pMDIWinInfo->WindowType,
  284. FALSE);
  285. ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
  286. #ifdef SEP_WAITHANDLE
  287. if (pQueue->hPrinterWait) {
  288. ClosePrinter(pQueue->hPrinterWait);
  289. pQueue->hPrinterWait = NULL;
  290. }
  291. #endif
  292. //
  293. // Try again
  294. //
  295. rc = GetGeneric( (PROC)GetPrinter, 2, (LPBYTE *)&pNewPrinter,
  296. cbNewPrinterBuf, &cbNewPrinterBuf,
  297. pQueue->hPrinter, NULL );
  298. }
  299. if (rc) {
  300. if( pQueue->pPrinter )
  301. FreeSplMem( pQueue->pPrinter );
  302. pQueue->pPrinter = pNewPrinter;
  303. pQueue->cbPrinterBuf = cbNewPrinterBuf;
  304. pQueue->pMDIWinInfo->Status &= ~PRINTER_STATUS_UNKNOWN;
  305. } else {
  306. DBGMSG( DBG_WARNING, ("GetPrinter failed for %ls: Error %d\n",
  307. pQueue->pPrinterName, pQueue->Error ) );
  308. pQueue->pMDIWinInfo->Status |= PRINTER_STATUS_UNKNOWN;
  309. if( pQueue->pPrinter )
  310. FreeSplMem( pQueue->pPrinter );
  311. if( pNewPrinter )
  312. FreeSplMem( pNewPrinter );
  313. pQueue->pPrinter = NULL;
  314. pQueue->cbPrinterBuf = 0;
  315. FreeJobInfo( pQueue );
  316. return FALSE;
  317. }
  318. }
  319. if( *pFlags & PRINTER_CHANGE_JOB )
  320. {
  321. /* Try to enumerate a buffer big enough to fill three pages of information,
  322. * so that we can scroll up or down a full page before it becomes necessary
  323. * to refresh the buffer. (Though with a refresh rate of once per second,
  324. * this will probably happen anyway.)
  325. * Note that pQueue->FirstEnumJob was set in Refresh (printman.c).
  326. * If it is 0, we may be currently scrolled to the top of the list,
  327. * in which case the buffer will extend two pages forward.
  328. */
  329. TryEnumJobs = ( pQueue->pMDIWinInfo->cNumLines * 3 );
  330. if( cbNewJobsBuf = pQueue->cbJobsBuf )
  331. pNewJobs = AllocSplMem( cbNewJobsBuf );
  332. DBG_IN_PROTECTED_DATA( pQueue->pMDIWinInfo );
  333. LEAVE_PROTECTED_DATA( pQueue->pMDIWinInfo );
  334. ENTER_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
  335. rc = ENUM_JOBS( pQueue->hPrinter,
  336. pQueue->FirstEnumJob,
  337. TryEnumJobs,
  338. 2,
  339. pNewJobs,
  340. cbNewJobsBuf,
  341. &cbNewJobsBuf,
  342. &cNewJobs );
  343. LEAVE_PROTECTED_HANDLE( pQueue->pMDIWinInfo );
  344. ENTER_PROTECTED_DATA( pQueue->pMDIWinInfo );
  345. if( rc )
  346. {
  347. DBGMSG( DBG_TRACE, ( "EnumJobs returned %d job%s @%08x in %d (0x%x) bytes for %s\n",
  348. cNewJobs, ( cNewJobs == 1 ? " " : "s" ),
  349. pNewJobs, cbNewJobsBuf, cbNewJobsBuf, pQueue->pPrinterName ) );
  350. if( pQueue->pJobs )
  351. {
  352. FreeSplMem( pQueue->pJobs );
  353. }
  354. /* Free up the previously allocated buffer
  355. * if we don't need it any more:
  356. */
  357. if( pNewJobs && ( cNewJobs == 0 ) )
  358. {
  359. DBGMSG( DBG_TRACE, ( "Freeing %d (0x%x) bytes @%08x\n",
  360. cbNewJobsBuf, cbNewJobsBuf, pNewJobs ) );
  361. FreeSplMem( pNewJobs );
  362. pNewJobs = NULL;
  363. cbNewJobsBuf = 0;
  364. }
  365. pQueue->pJobs = pNewJobs;
  366. pQueue->cbJobsBuf = cbNewJobsBuf;
  367. /* We shouldn't really get here if pQueue->pPrinter is non-NULL,
  368. * but it seems to be happening sometimes.
  369. */
  370. if( pQueue->pPrinter )
  371. pQueue->cJobs = pQueue->pPrinter->cJobs;
  372. else
  373. pQueue->cJobs = 0;
  374. pQueue->cEnumJobs = cNewJobs;
  375. }
  376. else
  377. {
  378. Error = GetLastError( );
  379. DBGMSG( DBG_WARNING, ("EnumJobs failed for %ls: Error %d\n",
  380. pQueue->pPrinterName, Error) );
  381. if( Error != ERROR_INSUFFICIENT_BUFFER )
  382. {
  383. FreeJobInfo( pQueue );
  384. pQueue->Error = Error;
  385. }
  386. }
  387. if( pQueue->pJobs )
  388. {
  389. SelectedJobIndex = GetSelectedJobIndex( pQueue );
  390. DBGMSG( DBG_TRACE, ( "Selected job index == %d\n", SelectedJobIndex ) );
  391. /* The selected job may have been scrolled out of buffer range.
  392. * In this case we allocate some job info for it:
  393. */
  394. if( ( pQueue->SelJobId ) && ( SelectedJobIndex == -1 ) )
  395. {
  396. DBGMSG( DBG_TRACE, ( "Selected job is scrolled out of range\n" ) );
  397. /* If it's just gone out of range, set the selected-job pointer
  398. * to NULL, so we don't try to Realloc part of the buffer.
  399. * (cbSelJob is non-null if we were out of range last time round,
  400. * because we allocated a job info structure.)
  401. */
  402. if( pQueue->cbSelJob == 0 )
  403. pQueue->pSelJob = NULL;
  404. pQueue->pSelJob = UpdateJobInfo( pQueue->hPrinter,
  405. pQueue->SelJobId,
  406. pQueue->pSelJob,
  407. &pQueue->cbSelJob );
  408. /* If the returned job info is NULL, either the job is no longer
  409. * around, or there was some sort of error.
  410. * In either case, deselect the current job:
  411. */
  412. if( !pQueue->pSelJob )
  413. {
  414. pQueue->SelJobId = 0;
  415. pQueue->pMDIWinInfo->ObjSelected = NOSELECTION;
  416. }
  417. }
  418. /* Otherwise just point the selected-job pointer at the appropriate
  419. * bit of the buffer:
  420. */
  421. else
  422. {
  423. /* If there was a job info allocated earlier, free it up.
  424. * cbSelJob must be 0 if there is no specially allocated buffer:
  425. */
  426. if( pQueue->cbSelJob )
  427. {
  428. FreeSplMem( pQueue->pSelJob );
  429. pQueue->pSelJob = NULL;
  430. pQueue->cbSelJob = 0;
  431. }
  432. if( pQueue->SelJobId )
  433. {
  434. pQueue->pSelJob = &pQueue->pJobs[SelectedJobIndex];
  435. pQueue->pMDIWinInfo->ObjSelected = ( pQueue->FirstEnumJob
  436. + SelectedJobIndex );
  437. DBGMSG( DBG_TRACE, ( "Selected job == %08x\n", pQueue->pSelJob ) );
  438. }
  439. }
  440. }
  441. else
  442. {
  443. /* Make sure any previous selection is canceled:
  444. */
  445. pQueue->pSelJob = NULL;
  446. pQueue->SelJobId = 0;
  447. pQueue->pMDIWinInfo->ObjSelected = NOSELECTION;
  448. }
  449. }
  450. return TRUE;
  451. }
  452. /*
  453. *
  454. */
  455. VOID FreeJobInfo( PQUEUE pQueue )
  456. {
  457. if (pQueue->pJobs)
  458. FreeSplMem(pQueue->pJobs);
  459. pQueue->pJobs = NULL;
  460. pQueue->cbJobsBuf = 0;
  461. pQueue->cEnumJobs = 0;
  462. pQueue->cJobs = 0;
  463. }
  464. /* OpenPrinterForSpecifiedAccess
  465. *
  466. * Attempts to open the printer for the requested access.
  467. * The following access permissions are valid:
  468. *
  469. * PRINTER_ALL_ACCESS
  470. * PRINTER_READ
  471. * READ_CONTROL
  472. *
  473. * If PRINTER_ACCESS_HIGHEST_PERMITTED is specified,
  474. * this function will attempt to open the printer using each of the above
  475. * permissions until it is successful.
  476. *
  477. */
  478. BOOL OpenPrinterForSpecifiedAccess(
  479. LPTSTR pName,
  480. LPHANDLE pHandle,
  481. DWORD AccessRequested,
  482. OPTIONAL PDWORD pAccessGranted )
  483. {
  484. PRINTER_DEFAULTS PrinterDefaults;
  485. BOOL rc = FALSE;
  486. BOOL TryAll = FALSE;
  487. PrinterDefaults.pDatatype = NULL;
  488. PrinterDefaults.pDevMode = NULL;
  489. switch( AccessRequested )
  490. {
  491. case PRINTER_ACCESS_HIGHEST_PERMITTED:
  492. TryAll = TRUE;
  493. /* fall through ... */
  494. case PRINTER_ALL_ACCESS:
  495. PrinterDefaults.DesiredAccess = PRINTER_ALL_ACCESS;
  496. rc = OpenPrinter( pName, pHandle, &PrinterDefaults );
  497. if( rc || !TryAll || (( GetLastError( ) != ERROR_ACCESS_DENIED ) &&
  498. ( GetLastError( ) != ERROR_PRIVILEGE_NOT_HELD)) )
  499. break;
  500. case PRINTER_READ:
  501. PrinterDefaults.DesiredAccess = PRINTER_READ;
  502. rc = OpenPrinter( pName, pHandle, &PrinterDefaults );
  503. if( rc || !TryAll || (( GetLastError( ) != ERROR_ACCESS_DENIED ) &&
  504. ( GetLastError( ) != ERROR_PRIVILEGE_NOT_HELD)) )
  505. break;
  506. case READ_CONTROL:
  507. PrinterDefaults.DesiredAccess = READ_CONTROL;
  508. rc = OpenPrinter( pName, pHandle, &PrinterDefaults );
  509. }
  510. if( pAccessGranted )
  511. {
  512. if( rc )
  513. *pAccessGranted = PrinterDefaults.DesiredAccess;
  514. else
  515. *pAccessGranted = PRINTER_ACCESS_DENIED;
  516. }
  517. return rc;
  518. }