Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1934 lines
40 KiB

  1. /*++
  2. Copyright (C) Microsoft Corporation, 1995 - 1998
  3. All rights reserved.
  4. Module Name:
  5. datar.cxx
  6. Abstract:
  7. VDataRefresh routines. Handles talking to downlevel clients
  8. (NT 3.5, wfw, lm, win95) which do not support full notifications.
  9. Note that the spooler simulates all single DWORD notifications
  10. for down-down level clients (wfw, lm, win95) so we don't have
  11. to handle polling.
  12. Author:
  13. Albert Ting (AlbertT) 07-12-95
  14. Revision History:
  15. --*/
  16. #include "precomp.hxx"
  17. #pragma hdrstop
  18. #if DBG
  19. //#define DBG_DATARINFO DBG_INFO
  20. #define DBG_DATARINFO DBG_NONE
  21. #endif
  22. /********************************************************************
  23. VDataRefresh handling: downlevel case.
  24. ********************************************************************/
  25. VDataRefresh::
  26. VDataRefresh(
  27. IN MDataClient* pDataClient,
  28. IN PFIELD_TABLE pFieldTable,
  29. IN DWORD fdwWatch
  30. ) : VData( pDataClient, pFieldTable ), _fdwWatch( fdwWatch )
  31. {
  32. ExecGuard._hPrinterWait = NULL;
  33. }
  34. VDataRefresh::
  35. ~VDataRefresh(
  36. VOID
  37. )
  38. {
  39. SPLASSERT( !ExecGuard._hPrinterWait );
  40. }
  41. VOID
  42. VDataRefresh::
  43. vProcessNotifyWork(
  44. IN TNotify* pNotify
  45. )
  46. {
  47. UNREFERENCED_PARAMETER( pNotify );
  48. DWORD dwChange;
  49. //
  50. // Notification caught. We must signal that caught it before
  51. // issuing the refresh, since there may be notifications between
  52. // the refresh and the FNPCN, which would be lost.
  53. //
  54. // Just issue a refresh since we don't support hot notifications.
  55. //
  56. BOOL bSuccess = FindNextPrinterChangeNotification( m_shNotify,
  57. &dwChange,
  58. 0,
  59. NULL );
  60. if( !bSuccess ){
  61. DBGMSG( DBG_WARN,
  62. ( "DataRefresh.vProcessNotifyWork: %x FNPCN %x failed: %d\n",
  63. this,
  64. static_cast<HANDLE>(m_shNotify),
  65. GetLastError( )));
  66. INFO Info;
  67. Info.dwData = TPrinter::kExecReopen | TPrinter::kExecDelay;
  68. _pDataClient->vContainerChanged( kContainerStateVar, Info );
  69. return;
  70. }
  71. //
  72. // Filter out any extranous watch flags that were set. This
  73. // may happen when the printer goes down and all flags are set.
  74. //
  75. if( dwChange & ~_fdwWatch ){
  76. DBGMSG( DBG_WARN,
  77. ( "VDataRefresh:vProcessNotifyWork: extra flags %x: %x %x\n",
  78. this, dwChange, _fdwWatch ));
  79. }
  80. dwChange &= _fdwWatch;
  81. CONTAINER_CHANGE ContainerChange = kContainerNull;
  82. INFO Info;
  83. Info.dwData = TPrinter::kExecRefresh;
  84. if( dwChange & PRINTER_CHANGE_PRINTER ){
  85. Info.dwData |= TPrinter::kExecRefreshContainer;
  86. }
  87. if( dwChange & PRINTER_CHANGE_JOB ){
  88. Info.dwData |= TPrinter::kExecRefreshItem;
  89. }
  90. _pDataClient->vContainerChanged( kContainerStateVar, Info );
  91. }
  92. /********************************************************************
  93. Worker thread functions for Refresh.
  94. ********************************************************************/
  95. STATEVAR
  96. VDataRefresh::
  97. svNotifyStart(
  98. IN STATEVAR StateVar
  99. )
  100. /*++
  101. Routine Description:
  102. Begin downlevel notifications.
  103. HACK: To support downlevel providers that don't support
  104. F*PCN calls, we must open a separate handle.
  105. Arguments:
  106. Return Value:
  107. --*/
  108. {
  109. TStatus Status;
  110. TStatusB bStatus;
  111. ExecGuard._hPrinterWait = _pDataClient->hPrinterNew();
  112. if( !ExecGuard._hPrinterWait ){
  113. goto Fail;
  114. }
  115. //
  116. // Get the notification handle.
  117. //
  118. m_shNotify = FindFirstPrinterChangeNotification(
  119. ExecGuard._hPrinterWait,
  120. _fdwWatch,
  121. 0,
  122. 0 );
  123. if( !m_shNotify )
  124. {
  125. DBGMSG( DBG_WARN, ( "DataRefresh.svNotifyStart: FFPCN failed %d\n", GetLastError( )));
  126. goto Fail;
  127. }
  128. DBGMSG( DBG_NOTIFY,
  129. ( "DataRefresh.svNotifyStart: %x FFPCN success returns 0x%x\n",
  130. _pDataClient, static_cast<HANDLE>(m_shNotify) ));
  131. //
  132. // Successfully opened, request that it be registered and then
  133. // refresh.
  134. //
  135. return (StateVar & ~TPrinter::kExecNotifyStart) |
  136. TPrinter::kExecRegister | TPrinter::kExecRefreshAll;
  137. Fail:
  138. //
  139. // Force a reopen. Everything gets reset (handles closed, etc.) when
  140. // the reopen occurs.
  141. //
  142. return StateVar | TPrinter::kExecDelay | TPrinter::kExecReopen;
  143. }
  144. STATEVAR
  145. VDataRefresh::
  146. svNotifyEnd(
  147. IN STATEVAR StateVar
  148. )
  149. /*++
  150. Routine Description:
  151. Stop downlevel notifications.
  152. Arguments:
  153. Return Value:
  154. --*/
  155. {
  156. TStatusB bStatus;
  157. DBGMSG( DBG_NOTIFY, ( "DataRefresh.svNotifyEnd: handle %x\n", static_cast<HANDLE>(m_shNotify) ));
  158. //
  159. // Unregister from TNotify.
  160. //
  161. _pPrintLib->pNotify()->sUnregister( this );
  162. //
  163. // If we have a notification event, close it.
  164. //
  165. m_shNotify = NULL;
  166. //
  167. // Close our separate printer.
  168. //
  169. if( ExecGuard._hPrinterWait ){
  170. bStatus DBGCHK = ClosePrinter( ExecGuard._hPrinterWait );
  171. ExecGuard._hPrinterWait = NULL;
  172. }
  173. return StateVar & ~TPrinter::kExecNotifyEnd;
  174. }
  175. /********************************************************************
  176. Static services.
  177. ********************************************************************/
  178. BOOL
  179. VDataRefresh::
  180. bGetPrinter(
  181. IN HANDLE hPrinter,
  182. IN DWORD dwLevel,
  183. IN OUT PVOID* ppvBuffer, CHANGE
  184. IN OUT PDWORD pcbBuffer
  185. )
  186. /*++
  187. Routine Description:
  188. Gets printer information, reallocing as necessary.
  189. Arguments:
  190. hPrinter - Printer to query.
  191. dwLevel - PRINTER_INFO_x level to retrieve.
  192. ppvBuffer - Buffer to store information. If *ppvBuffer is
  193. NULL, then it is allocated. On failure, this buffer is
  194. freed and NULLed
  195. pcbBuffer - Initial buffer size. On exit, actual.
  196. Return Value:
  197. TRUE = success, FALSE = fail.
  198. --*/
  199. {
  200. DWORD cbNeeded;
  201. //
  202. // Pre-initialize *pcbPrinter if it's not set.
  203. //
  204. if( !*pcbBuffer ){
  205. *pcbBuffer = kMaxPrinterInfo2;
  206. }
  207. Retry:
  208. SPLASSERT( *pcbBuffer < 0x100000 );
  209. if( !( *ppvBuffer )){
  210. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  211. if( !*ppvBuffer ){
  212. *pcbBuffer = 0;
  213. return FALSE;
  214. }
  215. }
  216. if( !GetPrinter( hPrinter,
  217. dwLevel,
  218. (PBYTE)*ppvBuffer,
  219. *pcbBuffer,
  220. &cbNeeded )){
  221. FreeMem( *ppvBuffer );
  222. *ppvBuffer = NULL;
  223. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  224. *pcbBuffer = 0;
  225. return FALSE;
  226. }
  227. *pcbBuffer = cbNeeded + kExtraPrinterBufferBytes;
  228. SPLASSERT( *pcbBuffer < 0x100000 );
  229. goto Retry;
  230. }
  231. return TRUE;
  232. }
  233. BOOL
  234. VDataRefresh::
  235. bGetJob(
  236. IN HANDLE hPrinter,
  237. IN DWORD dwJobId,
  238. IN DWORD dwLevel,
  239. IN OUT PVOID* ppvBuffer, CHANGE
  240. IN OUT PDWORD pcbBuffer
  241. )
  242. /*++
  243. Routine Description:
  244. Gets printer job information, reallocing as necessary.
  245. Arguments:
  246. hPrinter - Printer to query.
  247. dwLevel - JOB_INFO_x level to retrieve.
  248. ppvBuffer - Buffer to store information. If *ppvBuffer is
  249. NULL, then it is allocated. On failure, this buffer is
  250. freed and NULLed
  251. pcbBuffer - Initial buffer size. On exit, actual.
  252. Return Value:
  253. TRUE = success, FALSE = fail.
  254. --*/
  255. {
  256. DWORD cbNeeded;
  257. //
  258. // Pre-initialize *pcbPrinter if it's not set.
  259. //
  260. if( !*pcbBuffer ){
  261. *pcbBuffer = kInitialJobHint;
  262. }
  263. Retry:
  264. SPLASSERT( *pcbBuffer < 0x100000 );
  265. if( !( *ppvBuffer )){
  266. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  267. if( !*ppvBuffer ){
  268. *pcbBuffer = 0;
  269. return FALSE;
  270. }
  271. }
  272. if( !GetJob( hPrinter,
  273. dwJobId,
  274. dwLevel,
  275. (PBYTE)*ppvBuffer,
  276. *pcbBuffer,
  277. &cbNeeded )){
  278. FreeMem( *ppvBuffer );
  279. *ppvBuffer = NULL;
  280. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  281. *pcbBuffer = 0;
  282. return FALSE;
  283. }
  284. *pcbBuffer = cbNeeded + kExtraPrinterBufferBytes;
  285. SPLASSERT( *pcbBuffer < 0x100000 );
  286. goto Retry;
  287. }
  288. return TRUE;
  289. }
  290. BOOL
  291. VDataRefresh::
  292. bGetPrinterDriver(
  293. IN HANDLE hPrinter,
  294. IN LPCTSTR pszEnvironment,
  295. IN DWORD dwLevel,
  296. IN OUT PVOID* ppvBuffer, CHANGE
  297. IN OUT PDWORD pcbBuffer
  298. )
  299. /*++
  300. Routine Description:
  301. Gets printer driver information, reallocing as necessary.
  302. Arguments:
  303. hPrinter - Printer to query.
  304. pszEnvironment - Environment.
  305. dwLevel - DRIVER_INFO_x level to retrieve.
  306. ppvBuffer - Buffer to store information. If *ppvBuffer is
  307. NULL, then it is allocated. On failure, this buffer is
  308. freed and NULLed
  309. pcbBuffer - Initial buffer size. On exit, actual.
  310. Return Value:
  311. TRUE = success, FALSE = fail.
  312. --*/
  313. {
  314. DWORD cbNeeded;
  315. //
  316. // Pre-initialize *pcbPrinter if it's not set.
  317. //
  318. if( !*pcbBuffer ){
  319. *pcbBuffer = kInitialDriverInfo3Hint;
  320. }
  321. Retry:
  322. if( !( *ppvBuffer )){
  323. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  324. if( !*ppvBuffer ){
  325. *pcbBuffer = 0;
  326. return FALSE;
  327. }
  328. }
  329. if( !GetPrinterDriver( hPrinter,
  330. (LPTSTR)pszEnvironment,
  331. dwLevel,
  332. (PBYTE)*ppvBuffer,
  333. *pcbBuffer,
  334. &cbNeeded )){
  335. FreeMem( *ppvBuffer );
  336. *ppvBuffer = NULL;
  337. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  338. *pcbBuffer = 0;
  339. return FALSE;
  340. }
  341. *pcbBuffer = cbNeeded;
  342. goto Retry;
  343. }
  344. return TRUE;
  345. }
  346. BOOL
  347. VDataRefresh::
  348. bEnumJobs(
  349. IN HANDLE hPrinter,
  350. IN DWORD dwLevel,
  351. IN OUT PVOID* ppvBuffer, CHANGE
  352. IN OUT PDWORD pcbBuffer,
  353. OUT PDWORD pcJobs
  354. )
  355. /*++
  356. Routine Description:
  357. Enumerates job information, reallocing as necessary.
  358. Arguments:
  359. hPrinter - Printer to query.
  360. dwLevel - JOB_INFO_x level to retrieve.
  361. ppvBuffer - Buffer to store information. If *ppvBuffer is
  362. NULL, then it is allocated. On failure, this buffer is
  363. freed and NULLed
  364. pcbBuffer - Initial buffer size. On exit, actual.
  365. pcJobs - Number of jobs returned.
  366. Return Value:
  367. TRUE = success, FALSE = fail.
  368. --*/
  369. {
  370. DWORD cbNeeded;
  371. //
  372. // Pre-initialize *pcbPrinter if it's not set.
  373. //
  374. if( !*pcbBuffer ){
  375. *pcbBuffer = kInitialJobHint;
  376. }
  377. Retry:
  378. if( !( *ppvBuffer )){
  379. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  380. if( !*ppvBuffer ){
  381. *pcbBuffer = 0;
  382. *pcJobs = 0;
  383. return FALSE;
  384. }
  385. }
  386. if( !EnumJobs( hPrinter,
  387. 0,
  388. (DWORD)-1,
  389. dwLevel,
  390. (PBYTE)*ppvBuffer,
  391. *pcbBuffer,
  392. &cbNeeded,
  393. pcJobs )){
  394. FreeMem( *ppvBuffer );
  395. *ppvBuffer = NULL;
  396. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  397. *pcbBuffer = 0;
  398. *pcJobs = 0;
  399. return FALSE;
  400. }
  401. *pcbBuffer = cbNeeded + kExtraJobBufferBytes;
  402. goto Retry;
  403. }
  404. return TRUE;
  405. }
  406. BOOL
  407. VDataRefresh::
  408. bEnumPrinters(
  409. IN DWORD dwFlags,
  410. IN LPCTSTR pszServer,
  411. IN DWORD dwLevel,
  412. IN OUT PVOID* ppvBuffer, CHANGE
  413. IN OUT PDWORD pcbBuffer,
  414. OUT PDWORD pcPrinters
  415. )
  416. /*++
  417. Routine Description:
  418. Enumerates printer information, reallocing as necessary.
  419. Arguments:
  420. dwFlags - Scope of query.
  421. pszServer - Server to query.
  422. dwLevel - PRINTER_INFO_x level to retrieve.
  423. ppvBuffer - Buffer to store information. If *ppvBuffer is
  424. NULL, then it is allocated. On failure, this buffer is
  425. freed and NULLed
  426. pcbBuffer - Initial buffer size. On exit, actual.
  427. pcPrinters - Number of printers returned.
  428. Return Value:
  429. TRUE = success, FALSE = fail.
  430. --*/
  431. {
  432. DWORD cbNeeded;
  433. //
  434. // Pre-initialize *pcbPrinter if it's not set.
  435. //
  436. if( !*pcbBuffer ){
  437. *pcbBuffer = kInitialPrinterHint;
  438. }
  439. Retry:
  440. if( !( *ppvBuffer )){
  441. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  442. if( !*ppvBuffer ){
  443. *pcbBuffer = 0;
  444. *pcPrinters = 0;
  445. return FALSE;
  446. }
  447. }
  448. if( !EnumPrinters( dwFlags,
  449. (LPTSTR)pszServer,
  450. dwLevel,
  451. (PBYTE)*ppvBuffer,
  452. *pcbBuffer,
  453. &cbNeeded,
  454. pcPrinters )){
  455. FreeMem( *ppvBuffer );
  456. *ppvBuffer = NULL;
  457. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  458. *pcbBuffer = 0;
  459. *pcPrinters = 0;
  460. return FALSE;
  461. }
  462. *pcbBuffer = cbNeeded;
  463. goto Retry;
  464. }
  465. return TRUE;
  466. }
  467. BOOL
  468. VDataRefresh::
  469. bEnumDrivers(
  470. IN LPCTSTR pszServer,
  471. IN LPCTSTR pszEnvironment,
  472. IN DWORD dwLevel,
  473. IN OUT PVOID *ppvBuffer, CHANGE
  474. IN OUT PDWORD pcbBuffer,
  475. OUT PDWORD pcDrivers
  476. )
  477. /*++
  478. Routine Description:
  479. Enumerates driver information, reallocing as necessary.
  480. Arguments:
  481. dwFlags - Scope of query.
  482. pszServer - Server to query.
  483. dwLevel - DRIVER_INFO_x level to retrieve.
  484. ppvBuffer - Buffer to store information. If *ppvBuffer is
  485. NULL, then it is allocated. On failure, this buffer is
  486. freed and NULLed
  487. pcbBuffer - Initial buffer size. On exit, actual.
  488. pcPrinters - Number of printers returned.
  489. Return Value:
  490. TRUE = success, FALSE = fail.
  491. --*/
  492. {
  493. DWORD cbNeeded;
  494. //
  495. // Pre-initialize *pcbPrinter if it's not set.
  496. //
  497. if( !*pcbBuffer ){
  498. *pcbBuffer = kInitialDriverHint;
  499. }
  500. Retry:
  501. if( !( *ppvBuffer )){
  502. *ppvBuffer = (PVOID)AllocMem( *pcbBuffer );
  503. if( !*ppvBuffer ){
  504. *pcbBuffer = 0;
  505. *pcDrivers = 0;
  506. return FALSE;
  507. }
  508. }
  509. if( !EnumPrinterDrivers( (LPTSTR)pszServer,
  510. (LPTSTR)pszEnvironment,
  511. dwLevel,
  512. (PBYTE)*ppvBuffer,
  513. *pcbBuffer,
  514. &cbNeeded,
  515. pcDrivers )){
  516. FreeMem( *ppvBuffer );
  517. *ppvBuffer = NULL;
  518. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  519. *pcbBuffer = 0;
  520. *pcDrivers = 0;
  521. return FALSE;
  522. }
  523. *pcbBuffer = cbNeeded;
  524. goto Retry;
  525. }
  526. return TRUE;
  527. }
  528. /*++
  529. Routine Name:
  530. bGetDefaultDevMode
  531. Routine Description:
  532. Allocates the buffer needed to hold the dev mode.
  533. Arguments:
  534. hPrinter - Opened printer handle
  535. pszPrinterName - Pointer to printer name
  536. ppDevMode - Pointer where to return devmode
  537. bFillWithDefault - Flag indicates to fill dev mode with default information.
  538. TRUE fill allocated dev mode, FALSE do not fill
  539. Return Value:
  540. TRUE success, FALSE error occurred.
  541. --*/
  542. BOOL
  543. VDataRefresh::
  544. bGetDefaultDevMode(
  545. IN HANDLE hPrinter,
  546. IN LPCTSTR pszPrinterName,
  547. OUT PDEVMODE *ppDevMode,
  548. IN BOOL bFillWithDefault
  549. )
  550. {
  551. LONG lResult = 0;
  552. PDEVMODE pDevMode = NULL;
  553. //
  554. // Call document properties to get the size of the dev mode.
  555. //
  556. lResult = DocumentProperties( NULL,
  557. hPrinter,
  558. (LPTSTR)pszPrinterName,
  559. NULL,
  560. NULL,
  561. 0 );
  562. //
  563. // If the size of the dev mode was returned.
  564. //
  565. if( lResult > 0 )
  566. {
  567. pDevMode = (PDEVMODE)AllocMem( lResult );
  568. }
  569. //
  570. // If allocated then copy back the pointer.
  571. //
  572. if( pDevMode )
  573. {
  574. if( bFillWithDefault )
  575. {
  576. //
  577. // Call document properties to get the default dev mode.
  578. //
  579. lResult = DocumentProperties( NULL,
  580. hPrinter,
  581. (LPTSTR)pszPrinterName,
  582. pDevMode,
  583. NULL,
  584. DM_OUT_BUFFER );
  585. }
  586. if( lResult >= 0 )
  587. {
  588. *ppDevMode = pDevMode;
  589. }
  590. else
  591. {
  592. FreeMem( pDevMode );
  593. }
  594. }
  595. return *ppDevMode != NULL;
  596. }
  597. /*++
  598. Routine Name:
  599. bEnumPorts
  600. Routine Description:
  601. Enumerates the ports on the specified machine.
  602. Arguments:
  603. pszServer - Server to query.
  604. dwLevel - PORT_INFOX level to retrieve.
  605. ppvPorts - Buffer to store information. If *ppvBuffer is
  606. NULL, then it is allocated. On failure, this buffer is
  607. freed and NULLed
  608. pcbPorts - Initial buffer size. On exit, actual.
  609. pcPorts - Number of ports returned.
  610. Return Value:
  611. TRUE success, FALSE error occurred.
  612. --*/
  613. BOOL
  614. VDataRefresh::
  615. bEnumPorts(
  616. IN LPCTSTR pszServer,
  617. IN DWORD dwLevel,
  618. IN OUT PVOID *ppvPorts, CHANGE
  619. IN OUT PDWORD pcbPorts,
  620. OUT PDWORD pcPorts
  621. )
  622. {
  623. DWORD cbNeeded;
  624. //
  625. // Pre-initialize *pcbPorts if it's not set.
  626. //
  627. if( !*pcbPorts ){
  628. *pcbPorts = kEnumPortsHint;
  629. }
  630. Retry:
  631. if( !(*ppvPorts)){
  632. *ppvPorts = (PVOID)AllocMem( *pcbPorts );
  633. if( !*ppvPorts ){
  634. *pcbPorts = 0;
  635. *pcPorts = 0;
  636. DBGMSG( DBG_WARN,( "VDataRefresh::bEnumPorts can't alloc %d %d\n", *pcbPorts, GetLastError( )));
  637. return FALSE;
  638. }
  639. }
  640. if( !EnumPorts( (LPTSTR)pszServer,
  641. dwLevel,
  642. (PBYTE)*ppvPorts,
  643. *pcbPorts,
  644. &cbNeeded,
  645. pcPorts ) ){
  646. FreeMem( *ppvPorts );
  647. *ppvPorts = NULL;
  648. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  649. *pcbPorts = 0;
  650. *pcPorts = 0;
  651. return FALSE;
  652. }
  653. *pcbPorts = cbNeeded;
  654. goto Retry;
  655. }
  656. return TRUE;
  657. }
  658. /*++
  659. Routine Name:
  660. bEnumPortsMaxLevel
  661. Routine Description:
  662. Enumerates the ports on the specified machine. With maximum level
  663. specified.
  664. Arguments:
  665. pszServer - Server to query.
  666. dwLevel - Max PORT_INFOX level to retrieve. We try this level and
  667. decrement until dwLevel is zero.
  668. ppvPorts - Buffer to store information. If *ppvBuffer is
  669. NULL, then it is allocated. On failure, this buffer is
  670. freed and NULLed
  671. pcbPorts - Initial buffer size. On exit, actual.
  672. pcPorts - Number of ports returned.
  673. Return Value:
  674. TRUE success, FALSE error occurred.
  675. --*/
  676. BOOL
  677. VDataRefresh::
  678. bEnumPortsMaxLevel(
  679. IN LPCTSTR pszServer,
  680. IN PDWORD pdwLevel,
  681. IN OUT PVOID *ppvPorts, CHANGE
  682. IN OUT PDWORD pcbPorts,
  683. OUT PDWORD pcPorts
  684. )
  685. {
  686. BOOL bStatus = FALSE;
  687. //
  688. // Try all levels to level zero.
  689. //
  690. for( ; *pdwLevel; (*pdwLevel)-- )
  691. {
  692. bStatus = bEnumPorts( pszServer,
  693. *pdwLevel,
  694. ppvPorts,
  695. pcbPorts,
  696. pcPorts );
  697. //
  698. // If the call succeeded then we are done.
  699. //
  700. if( bStatus )
  701. {
  702. break;
  703. }
  704. else
  705. {
  706. //
  707. // The call failed and it is not invalid level then
  708. // exit with error.
  709. //
  710. if( GetLastError() != ERROR_INVALID_LEVEL )
  711. {
  712. break;
  713. }
  714. }
  715. }
  716. return bStatus;
  717. }
  718. /*++
  719. Routine Name:
  720. bEnumPorts
  721. Routine Description:
  722. Enumerates the ports on the specified machine.
  723. Arguments:
  724. pszServer - Server to query.
  725. dwLevel - PORT_INFOX level to retrieve.
  726. ppvPorts - Buffer to store information. If *ppvBuffer is
  727. NULL, then it is allocated. On failure, this buffer is
  728. freed and NULLed
  729. pcbPorts - Initial buffer size. On exit, actual.
  730. pcPorts - Number of ports returned.
  731. Return Value:
  732. TRUE success, FALSE error occurred.
  733. --*/
  734. BOOL
  735. VDataRefresh::
  736. bEnumMonitors(
  737. IN LPCTSTR pszServer,
  738. IN DWORD dwLevel,
  739. IN OUT PVOID *ppvMonitors, CHANGE
  740. IN OUT PDWORD pcbMonitors,
  741. OUT PDWORD pcMonitors
  742. )
  743. {
  744. DWORD cbNeeded;
  745. //
  746. // Pre-initialize *pcbMonitors if it's not set.
  747. //
  748. if( !*pcbMonitors ){
  749. *pcbMonitors = kEnumMonitorsHint;
  750. }
  751. Retry:
  752. if( !(*ppvMonitors)){
  753. *ppvMonitors = (PVOID)AllocMem( *pcbMonitors );
  754. if( !*ppvMonitors ){
  755. *pcbMonitors = 0;
  756. *pcMonitors = 0;
  757. DBGMSG( DBG_WARN,( "VDataRefresh::bEnumMonitors can't alloc %d %d\n", *pcbMonitors, GetLastError( )));
  758. return FALSE;
  759. }
  760. }
  761. if( !EnumMonitors( (LPTSTR)pszServer,
  762. dwLevel,
  763. (PBYTE)*ppvMonitors,
  764. *pcbMonitors,
  765. &cbNeeded,
  766. pcMonitors ) ){
  767. FreeMem( *ppvMonitors );
  768. *ppvMonitors = NULL;
  769. if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ){
  770. *pcbMonitors = 0;
  771. *pcMonitors = 0;
  772. return FALSE;
  773. }
  774. *pcbMonitors = cbNeeded;
  775. goto Retry;
  776. }
  777. return TRUE;
  778. }
  779. /********************************************************************
  780. TDataRJob
  781. ********************************************************************/
  782. TDataRJob::
  783. TDataRJob(
  784. IN MDataClient* pDataClient
  785. ) : VDataRefresh( pDataClient, &TDataNJob::gFieldTable, kfdwWatch )
  786. {
  787. ExecGuard._cbJobHint = kInitialJobHint;
  788. UIGuard._pJobs = NULL;
  789. }
  790. TDataRJob::
  791. ~TDataRJob(
  792. VOID
  793. )
  794. {
  795. FreeMem( UIGuard._pJobs );
  796. }
  797. /********************************************************************
  798. Data interface for Refresh.
  799. ********************************************************************/
  800. HITEM
  801. TDataRJob::
  802. GetItem(
  803. IN NATURAL_INDEX NaturalIndex
  804. ) const
  805. {
  806. SPLASSERT( UIGuard._pJobs );
  807. SPLASSERT( NaturalIndex < VData::UIGuard._cItems );
  808. return (HITEM)&UIGuard._pJobs[NaturalIndex];
  809. }
  810. HITEM
  811. TDataRJob::
  812. GetNextItem(
  813. IN HITEM hItem
  814. ) const
  815. {
  816. SPLASSERT( UIGuard._pJobs );
  817. //
  818. // NULL passed in, return first item.
  819. //
  820. if( !hItem ){
  821. return &UIGuard._pJobs[0];
  822. }
  823. PJOB_INFO_2 pJob2 = (PJOB_INFO_2)hItem;
  824. return (HITEM)( pJob2 + 1 );
  825. }
  826. INFO
  827. TDataRJob::
  828. GetInfo(
  829. IN HITEM hItem,
  830. IN DATA_INDEX DataIndex
  831. ) const
  832. {
  833. SPLASSERT( hItem );
  834. SPLASSERT( DataIndex < _pFieldTable->cFields );
  835. INFO Info = kInfoNull;
  836. PJOB_INFO_2 pJob2 = (PJOB_INFO_2)hItem;
  837. BOOL bString = FALSE;
  838. //
  839. // Translate the index into the appropriate field.
  840. //
  841. FIELD Field = _pFieldTable->pFields[DataIndex];
  842. switch( Field ){
  843. case JOB_NOTIFY_FIELD_DOCUMENT:
  844. Info.pszData = pJob2->pDocument;
  845. bString = TRUE;
  846. break;
  847. case JOB_NOTIFY_FIELD_STATUS:
  848. Info.dwData = pJob2->Status;
  849. break;
  850. case JOB_NOTIFY_FIELD_STATUS_STRING:
  851. Info.pszData = pJob2->pStatus;
  852. bString = TRUE;
  853. break;
  854. case JOB_NOTIFY_FIELD_USER_NAME:
  855. Info.pszData = pJob2->pUserName;
  856. bString = TRUE;
  857. break;
  858. case JOB_NOTIFY_FIELD_TOTAL_PAGES:
  859. Info.dwData = pJob2->TotalPages;
  860. break;
  861. case JOB_NOTIFY_FIELD_PAGES_PRINTED:
  862. //
  863. // In chicago, PagesPrinted is overloaded so that if
  864. // TotalPages is zero, PagesPrinted is actually BytesPrinted.
  865. //
  866. Info.dwData = pJob2->TotalPages ?
  867. pJob2->PagesPrinted :
  868. 0;
  869. break;
  870. case JOB_NOTIFY_FIELD_TOTAL_BYTES:
  871. Info.dwData = pJob2->Size;
  872. break;
  873. case JOB_NOTIFY_FIELD_BYTES_PRINTED:
  874. //
  875. // In chicago, PagesPrinted is overloaded so that if
  876. // TotalPages is zero, PagesPrinted is actually BytesPrinted.
  877. //
  878. Info.dwData = !pJob2->TotalPages ?
  879. pJob2->PagesPrinted :
  880. 0;
  881. break;
  882. case JOB_NOTIFY_FIELD_SUBMITTED:
  883. Info.pSystemTime = &pJob2->Submitted;
  884. break;
  885. case JOB_NOTIFY_FIELD_PORT_NAME:
  886. Info.pszData = gszNULL;
  887. break;
  888. default:
  889. DBGMSG( DBG_ERROR,
  890. ( "DataRJob.GetInfo: Unimplemented field %d\n", Field ));
  891. break;
  892. }
  893. if( bString && !Info.pszData ){
  894. Info.pszData = gszNULL;
  895. }
  896. return Info;
  897. }
  898. IDENT
  899. TDataRJob::
  900. GetId(
  901. IN HITEM hItem
  902. ) const
  903. {
  904. SPLASSERT( hItem );
  905. PJOB_INFO_2 pJob2 = (PJOB_INFO_2)hItem;
  906. return pJob2->JobId;
  907. }
  908. NATURAL_INDEX
  909. TDataRJob::
  910. GetNaturalIndex(
  911. IN IDENT Id,
  912. OUT PHITEM phItem OPTIONAL
  913. ) const
  914. {
  915. COUNT cItems = VData::UIGuard._cItems;
  916. PJOB_INFO_2 pJob2 = UIGuard._pJobs;
  917. if( phItem ){
  918. *phItem = NULL;
  919. }
  920. //
  921. // If no _pJobs, return 0. This may happen if during a refresh,
  922. // the selected item is deleted.
  923. //
  924. if( pJob2 ){
  925. //
  926. // Look for a JobId that matches ours.
  927. //
  928. COUNT i;
  929. for( i = 0; i < cItems; ++i ){
  930. if( pJob2[i].JobId == Id ){
  931. if( phItem ){
  932. *phItem = (HITEM)&pJob2[i];
  933. }
  934. return i;
  935. }
  936. }
  937. }
  938. DBGMSG( DBG_DATARINFO,
  939. ( "DataRefresh.GetNaturalIndex: Item %d not found (cItems = %d, pJob2 = %x) %x\n",
  940. Id, cItems, pJob2, this ));
  941. return kInvalidNaturalIndexValue;
  942. }
  943. STATEVAR
  944. TDataRJob::
  945. svRefresh(
  946. IN STATEVAR StateVar
  947. )
  948. /*++
  949. Routine Description:
  950. Refresh the printer data object.
  951. Arguments:
  952. Return Value:
  953. --*/
  954. {
  955. if( !m_shNotify )
  956. {
  957. return TPrinter::kExecReopen;
  958. }
  959. //
  960. // !! HACK !!
  961. //
  962. // Nuke extraneous refreshes by resetting m_shNotify.
  963. //
  964. if( !ResetEvent( m_shNotify ))
  965. {
  966. DBGMSG( DBG_ERROR, ( "DataRefresh.svRefresh: reset %x failed %d\n",
  967. static_cast<HANDLE>(m_shNotify), GetLastError( )));
  968. }
  969. //
  970. // Check if jobs need to be refreshed.
  971. //
  972. if( StateVar & TPrinter::kExecRefreshItem ){
  973. //
  974. // Attempt an enum of approximately the same size as last time.
  975. //
  976. DWORD cJobs = 0;
  977. DWORD cbJobs = ExecGuard._cbJobHint;
  978. PJOB_INFO_2 pJobs = (PJOB_INFO_2)AllocMem( cbJobs );
  979. if( !pJobs ){
  980. goto Fail;
  981. }
  982. TStatusB bStatus( DBG_WARN,
  983. RPC_S_SERVER_UNAVAILABLE,
  984. RPC_S_SERVER_TOO_BUSY,
  985. RPC_S_CALL_FAILED_DNE );
  986. bStatus DBGCHK = bEnumJobs( _pDataClient->hPrinter(),
  987. 2,
  988. (PVOID*)&pJobs,
  989. &cbJobs,
  990. &cJobs );
  991. if( bStatus ){
  992. ExecGuard._cbJobHint = cbJobs;
  993. //
  994. // Inform the printer that we have new data.
  995. // vRequestBlockProcess adopts pJobs, so we don't free it here.
  996. //
  997. vBlockAdd( cJobs, 0, (HBLOCK)pJobs );
  998. pJobs = NULL;
  999. }
  1000. FreeMem( pJobs );
  1001. if( !bStatus ){
  1002. //
  1003. // Failed; delay then reopen.
  1004. //
  1005. goto Fail;
  1006. }
  1007. }
  1008. //
  1009. // Check if the printer needs to be refreshed.
  1010. //
  1011. if( StateVar & TPrinter::kExecRefreshContainer ){
  1012. //
  1013. // Update printer name.
  1014. //
  1015. PPRINTER_INFO_2 pPrinter2 = NULL;
  1016. DWORD cbPrinter2 = kMaxPrinterInfo2;
  1017. TStatusB bStatus( DBG_WARN );
  1018. bStatus DBGCHK = TDataRJob::bGetPrinter( _pDataClient->hPrinter(),
  1019. 2,
  1020. (PVOID*)&pPrinter2,
  1021. &cbPrinter2 );
  1022. if( bStatus ){
  1023. //
  1024. // Inform the printer that we have new data.
  1025. // vRequestBlockProcess adopts pPrinter2, so we don't free it here.
  1026. //
  1027. vBlockAdd( kInvalidCountValue, 0, (HBLOCK)pPrinter2 );
  1028. pPrinter2 = NULL;
  1029. }
  1030. FreeMem( pPrinter2 );
  1031. if( !bStatus ){
  1032. goto Fail;
  1033. }
  1034. }
  1035. return StateVar & ~TPrinter::kExecRefreshAll;
  1036. Fail:
  1037. //
  1038. // If we get NERR_QNotFound, then this is a masq case where
  1039. // the printer is no longer shared. Don't bother retrying.
  1040. //
  1041. DWORD dwError = GetLastError();
  1042. if( dwError == NERR_QNotFound ){
  1043. INFO Info;
  1044. Info.dwData = kConnectStatusInvalidPrinterName;
  1045. _pDataClient->vContainerChanged( kContainerConnectStatus, Info );
  1046. return TPrinter::kExecError;
  1047. }
  1048. //
  1049. // !! LATER !!
  1050. //
  1051. // Put error in status bar.
  1052. //
  1053. SPLASSERT( dwError );
  1054. return StateVar | TPrinter::kExecReopen | TPrinter::kExecDelay;
  1055. }
  1056. /********************************************************************
  1057. UI Thread interaction routines.
  1058. ********************************************************************/
  1059. VOID
  1060. TDataRJob::
  1061. vBlockProcessImp(
  1062. IN DWORD dwParam1,
  1063. IN DWORD dwParam2,
  1064. IN HBLOCK hBlock ADOPT
  1065. )
  1066. /*++
  1067. Routine Description:
  1068. Take a job block and update the internal data structure. This
  1069. function will call back into _pPrinter to refresh the screen.
  1070. Arguments:
  1071. dwParam1 - job count
  1072. hBlock - PJOB_INFO_2 block
  1073. Return Value:
  1074. --*/
  1075. {
  1076. UNREFERENCED_PARAMETER( dwParam2 );
  1077. //
  1078. // If dwParam is an invalid count value, then we have printer
  1079. // information. Else it is job information.
  1080. //
  1081. if( dwParam1 == kInvalidCountValue ){
  1082. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)hBlock;
  1083. INFO Info;
  1084. //
  1085. // Update all printer information.
  1086. //
  1087. //
  1088. // Note: We do not update strServer, because the printer
  1089. // name in PRINTER_INFO_2 already includes the server name!
  1090. //
  1091. Info.pszData = pPrinter2->pPrinterName;
  1092. _pDataClient->vContainerChanged( kContainerName, Info );
  1093. Info.dwData = pPrinter2->Status;
  1094. _pDataClient->vContainerChanged( kContainerStatus, Info );
  1095. Info.dwData = pPrinter2->Attributes;
  1096. _pDataClient->vContainerChanged( kContainerAttributes, Info );
  1097. FreeMem( pPrinter2 );
  1098. } else {
  1099. //
  1100. // Must save the selections since we are deleting and
  1101. // re-adding them.
  1102. //
  1103. _pDataClient->vSaveSelections();
  1104. //
  1105. // No need to grab any critical sections since we are in
  1106. // the UI thread.
  1107. //
  1108. FreeMem( UIGuard._pJobs );
  1109. UIGuard._pJobs = (PJOB_INFO_2)hBlock;
  1110. VData::UIGuard._cItems = dwParam1;
  1111. //
  1112. // Job count is stored in dwParm; pass to vContainerChanged.
  1113. //
  1114. INFO Info;
  1115. Info.dwData = dwParam1;
  1116. _pDataClient->vContainerChanged( kContainerReloadItems, Info );
  1117. _pDataClient->vContainerChanged( kContainerRefreshComplete, kInfoNull );
  1118. _pDataClient->vRestoreSelections();
  1119. }
  1120. }
  1121. VOID
  1122. TDataRJob::
  1123. vBlockDelete(
  1124. IN HBLOCK hBlock
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Free a Block. Called when the PostMessage fails and the
  1129. job block needs to be destroyed.
  1130. Arguments:
  1131. hBlock - Job block to delete.
  1132. Return Value:
  1133. --*/
  1134. {
  1135. FreeMem( hBlock );
  1136. }
  1137. /********************************************************************
  1138. TDataRPrinter
  1139. ********************************************************************/
  1140. TDataRPrinter::
  1141. TDataRPrinter(
  1142. IN MDataClient* pDataClient
  1143. ) : VDataRefresh( pDataClient, &TDataNPrinter::gFieldTable, kfdwWatch )
  1144. {
  1145. ExecGuard._cbPrinterHint = kInitialPrinterHint;
  1146. UIGuard._pPrinters = NULL;
  1147. //
  1148. // Determine whether this is a printer or a server.
  1149. //
  1150. TCHAR szDataSource[kPrinterBufMax];
  1151. LPTSTR pszDataSource = _pDataClient->pszPrinterName( szDataSource );
  1152. _bSinglePrinter = TDataRPrinter::bSinglePrinter( pszDataSource );
  1153. }
  1154. TDataRPrinter::
  1155. ~TDataRPrinter(
  1156. VOID
  1157. )
  1158. {
  1159. FreeMem( UIGuard._pPrinters );
  1160. }
  1161. BOOL
  1162. TDataRPrinter::
  1163. bSinglePrinter(
  1164. LPCTSTR pszDataSource
  1165. )
  1166. {
  1167. BOOL bReturn = FALSE;
  1168. //
  1169. // Check if it's a single printer vs. a server. The only
  1170. // way I can think of doing this is to look for the format
  1171. // "\\server." This works fine for Win9x downlevel printers
  1172. // however fails for internet connected printers.
  1173. //
  1174. // So adding to the hack we will do a little more checking
  1175. // and look if the printer name has a prfix string of
  1176. // http:// or https://. So what we are saying is that printer
  1177. // names of this form are considered a masq printers.
  1178. //
  1179. if( pszDataSource )
  1180. {
  1181. bReturn = pszDataSource[0] == TEXT( '\\' ) &&
  1182. pszDataSource[1] == TEXT( '\\' ) &&
  1183. _tcschr( &pszDataSource[2], TEXT( '\\' ));
  1184. if( !bReturn )
  1185. {
  1186. bReturn = !_tcsnicmp( pszDataSource, gszHttpPrefix0, _tcslen(gszHttpPrefix0) ) ||
  1187. !_tcsnicmp( pszDataSource, gszHttpPrefix1, _tcslen(gszHttpPrefix1) );
  1188. }
  1189. }
  1190. return bReturn;
  1191. }
  1192. /********************************************************************
  1193. Data interface for Refresh.
  1194. ********************************************************************/
  1195. HITEM
  1196. TDataRPrinter::
  1197. GetItem(
  1198. IN NATURAL_INDEX NaturalIndex
  1199. ) const
  1200. {
  1201. SPLASSERT( UIGuard._pPrinters );
  1202. SPLASSERT( NaturalIndex < VData::UIGuard._cItems );
  1203. return (HITEM)&UIGuard._pPrinters[NaturalIndex];
  1204. }
  1205. HITEM
  1206. TDataRPrinter::
  1207. GetNextItem(
  1208. IN HITEM hItem
  1209. ) const
  1210. {
  1211. SPLASSERT( UIGuard._pPrinters );
  1212. //
  1213. // Requesting first item.
  1214. //
  1215. if( !hItem ){
  1216. SPLASSERT( VData::UIGuard._cItems > 0 );
  1217. return (HITEM)&UIGuard._pPrinters[0];
  1218. }
  1219. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)hItem;
  1220. return (HITEM)( pPrinter2 + 1 );
  1221. }
  1222. INFO
  1223. TDataRPrinter::
  1224. GetInfo(
  1225. IN HITEM hItem,
  1226. IN DATA_INDEX DataIndex
  1227. ) const
  1228. {
  1229. SPLASSERT( hItem );
  1230. SPLASSERT( DataIndex < _pFieldTable->cFields );
  1231. INFO Info = kInfoNull;
  1232. PPRINTER_INFO_2 pPrinter2 = (PPRINTER_INFO_2)hItem;
  1233. //
  1234. // Translate the index into the appropriate field.
  1235. //
  1236. FIELD Field = _pFieldTable->pFields[DataIndex];
  1237. BOOL bString = FALSE;
  1238. switch( Field ){
  1239. case PRINTER_NOTIFY_FIELD_PRINTER_NAME:
  1240. SPLASSERT( pPrinter2->pPrinterName );
  1241. //
  1242. // Skip the server prefix and extra backslash.
  1243. //
  1244. Info.pszData = pPrinter2->pPrinterName +
  1245. (pPrinter2->pServerName ? _tcslen( pPrinter2->pServerName ) + 1 : 0);
  1246. break;
  1247. case PRINTER_NOTIFY_FIELD_CJOBS:
  1248. Info.dwData = pPrinter2->cJobs;
  1249. break;
  1250. case PRINTER_NOTIFY_FIELD_ATTRIBUTES:
  1251. Info.dwData = pPrinter2->Attributes;
  1252. break;
  1253. case PRINTER_NOTIFY_FIELD_STATUS:
  1254. Info.dwData = pPrinter2->Status;
  1255. break;
  1256. case PRINTER_NOTIFY_FIELD_COMMENT:
  1257. Info.pszData = pPrinter2->pComment;
  1258. bString = TRUE;
  1259. break;
  1260. case PRINTER_NOTIFY_FIELD_LOCATION:
  1261. Info.pszData = pPrinter2->pLocation;
  1262. bString = TRUE;
  1263. break;
  1264. case PRINTER_NOTIFY_FIELD_DRIVER_NAME:
  1265. Info.pszData = pPrinter2->pDriverName;
  1266. bString = TRUE;
  1267. break;
  1268. case PRINTER_NOTIFY_FIELD_PORT_NAME:
  1269. Info.pszData = pPrinter2->pPortName;
  1270. bString = TRUE;
  1271. break;
  1272. default:
  1273. DBGMSG( DBG_ERROR,
  1274. ( "DataRPrinter.GetInfo: Unimplemented field %d\n", Field ));
  1275. break;
  1276. }
  1277. if( bString && !Info.pszData ){
  1278. Info.pszData = gszNULL;
  1279. }
  1280. return Info;
  1281. }
  1282. IDENT
  1283. TDataRPrinter::
  1284. GetId(
  1285. IN HITEM hItem
  1286. ) const
  1287. {
  1288. SPLASSERT( hItem );
  1289. return kInvalidIdentValue;
  1290. }
  1291. NATURAL_INDEX
  1292. TDataRPrinter::
  1293. GetNaturalIndex(
  1294. IN IDENT Id,
  1295. OUT PHITEM phItem OPTIONAL
  1296. ) const
  1297. {
  1298. UNREFERENCED_PARAMETER( Id );
  1299. UNREFERENCED_PARAMETER( phItem );
  1300. return kInvalidNaturalIndexValue;
  1301. }
  1302. STATEVAR
  1303. TDataRPrinter::
  1304. svRefresh(
  1305. IN STATEVAR StateVar
  1306. )
  1307. /*++
  1308. Routine Description:
  1309. Refresh the printer data object.
  1310. Arguments:
  1311. Return Value:
  1312. --*/
  1313. {
  1314. //
  1315. // !! HACK !!
  1316. //
  1317. // Nuke extraneous refreshes by resetting m_shNotify.
  1318. //
  1319. if( !ResetEvent( m_shNotify ))
  1320. {
  1321. DBGMSG( DBG_ERROR, ( "DataRefresh.svRefresh: reset %x failed %d\n",
  1322. static_cast<HANDLE>(m_shNotify), GetLastError( )));
  1323. }
  1324. //
  1325. // Attempt an enum of approximately the same size as last time.
  1326. //
  1327. DWORD cPrinters = 0;
  1328. DWORD cbPrinters = ExecGuard._cbPrinterHint;
  1329. PPRINTER_INFO_2 pPrinters = (PPRINTER_INFO_2)AllocMem( cbPrinters );
  1330. if( pPrinters ){
  1331. TStatusB bStatus;
  1332. if( _bSinglePrinter ){
  1333. cPrinters = 1;
  1334. bStatus DBGCHK = TDataRJob::bGetPrinter( _pDataClient->hPrinter(),
  1335. 2,
  1336. (PVOID*)&pPrinters,
  1337. &cbPrinters );
  1338. } else {
  1339. //
  1340. // It's a server, but it's stored in the printer name string
  1341. // since that's where we put the datasource.
  1342. //
  1343. TCHAR szServerBuffer[kPrinterBufMax];
  1344. LPTSTR pszServer = _pDataClient->pszPrinterName( szServerBuffer );
  1345. bStatus DBGCHK = bEnumPrinters( PRINTER_ENUM_NAME,
  1346. pszServer,
  1347. 2,
  1348. (PVOID*)&pPrinters,
  1349. &cbPrinters,
  1350. &cPrinters );
  1351. }
  1352. if( bStatus ){
  1353. ExecGuard._cbPrinterHint = cbPrinters;
  1354. //
  1355. // Inform the printer that we have new data.
  1356. // vRequestBlockProcess adopts pJobs, so we don't free it here.
  1357. //
  1358. vBlockAdd( cPrinters, 0, (HBLOCK)pPrinters );
  1359. return StateVar & ~TPrinter::kExecRefreshAll;
  1360. } else {
  1361. //
  1362. // If we get NERR_QNotFound, then this is a masq case where
  1363. // the printer is no longer shared. Don't bother retrying.
  1364. //
  1365. DWORD dwError = GetLastError();
  1366. INFO Info;
  1367. if( dwError == ERROR_ACCESS_DENIED ){
  1368. Info.dwData = kConnectStatusAccessDenied;
  1369. } else {
  1370. Info.dwData = kConnectStatusInvalidPrinterName;
  1371. }
  1372. _pDataClient->vContainerChanged( kContainerConnectStatus, Info );
  1373. return TPrinter::kExecError;
  1374. }
  1375. }
  1376. //
  1377. // !! LATER !!
  1378. //
  1379. // Put error in status bar.
  1380. //
  1381. SPLASSERT( GetLastError( ));
  1382. return StateVar | TPrinter::kExecReopen | TPrinter::kExecDelay;
  1383. }
  1384. /********************************************************************
  1385. UI Thread interaction routines.
  1386. ********************************************************************/
  1387. VOID
  1388. TDataRPrinter::
  1389. vBlockProcessImp(
  1390. IN DWORD dwParam1,
  1391. IN DWORD dwParam2,
  1392. IN HBLOCK hBlock ADOPT
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. Take a item block and update the internal data structure. This
  1397. function will call back into _pPrinter to refresh the screen.
  1398. Arguments:
  1399. dwParam1 - Item count
  1400. hBlock - PJOB_INFO_2 block
  1401. Return Value:
  1402. --*/
  1403. {
  1404. UNREFERENCED_PARAMETER( dwParam2 );
  1405. //
  1406. // No need to grab any critical sections since we are in
  1407. // the UI thread.
  1408. //
  1409. FreeMem( UIGuard._pPrinters );
  1410. UIGuard._pPrinters = (PPRINTER_INFO_2)hBlock;
  1411. VData::UIGuard._cItems = dwParam1;
  1412. //
  1413. // Item count is stored in dwParm; pass to vContainerChanged.
  1414. //
  1415. INFO Info;
  1416. Info.dwData = dwParam1;
  1417. _pDataClient->vContainerChanged( kContainerReloadItems, Info );
  1418. _pDataClient->vContainerChanged( kContainerRefreshComplete, kInfoNull );
  1419. }
  1420. VOID
  1421. TDataRPrinter::
  1422. vBlockDelete(
  1423. IN HBLOCK hBlock
  1424. )
  1425. /*++
  1426. Routine Description:
  1427. Free a Block. Called when the PostMessage fails and the
  1428. Item block needs to be destroyed.
  1429. Arguments:
  1430. hBlock - Item block to delete.
  1431. Return Value:
  1432. --*/
  1433. {
  1434. FreeMem( hBlock );
  1435. }