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.

934 lines
30 KiB

  1. /*
  2. * HrPrinterEntry.c v0.10
  3. * Generated in conjunction with Management Factory scripts:
  4. * script version: SNMPv1, 0.16, Apr 25, 1996
  5. * project: D:\TEMP\EXAMPLE\HOSTMIB
  6. ****************************************************************************
  7. * *
  8. * (C) Copyright 1995 DIGITAL EQUIPMENT CORPORATION *
  9. * *
  10. * This software is an unpublished work protected under the *
  11. * the copyright laws of the United States of America, all *
  12. * rights reserved. *
  13. * *
  14. * In the event this software is licensed for use by the United *
  15. * States Government, all use, duplication or disclosure by the *
  16. * United States Government is subject to restrictions as set *
  17. * forth in either subparagraph (c)(1)(ii) of the Rights in *
  18. * Technical Data And Computer Software Clause at DFARS *
  19. * 252.227-7013, or the Commercial Computer Software Restricted *
  20. * Rights Clause at FAR 52.221-19, whichever is applicable. *
  21. * *
  22. ****************************************************************************
  23. *
  24. * Facility:
  25. *
  26. * Windows NT SNMP Extension Agent
  27. *
  28. * Abstract:
  29. *
  30. * This module contains the code for dealing with the get, set, and
  31. * instance name routines for the HrPrinterEntry. Actual instrumentation code is
  32. * supplied by the developer.
  33. *
  34. * Functions:
  35. *
  36. * A get and set routine for each attribute in the class.
  37. *
  38. * The routines for instances within the class.
  39. *
  40. * Author:
  41. *
  42. * D. D. Burns @ Webenable Inc
  43. *
  44. * Revision History:
  45. *
  46. * V1.00 - 04/27/97 D. D. Burns Genned: Thu Nov 07 16:42:50 1996
  47. *
  48. */
  49. #include <windows.h>
  50. #include <malloc.h>
  51. #include <snmp.h>
  52. #include "mib.h"
  53. #include "smint.h"
  54. #include "hostmsmi.h"
  55. #include "user.h" /* Developer supplied include file */
  56. #include "HMCACHE.H" /* Cache-related definitions */
  57. #include "HRDEVENT.H" /* HrDevice Table related definitions */
  58. #include <winspool.h> /* Needed to acquire printer-status*/
  59. /*
  60. * GetHrPrinterStatus
  61. * The current status of this printer device.
  62. *
  63. * Gets the value for HrPrinterStatus.
  64. *
  65. * Arguments:
  66. *
  67. * outvalue address to return variable value
  68. * accesss Reserved for future security use
  69. * instance address of instance name as ordered native
  70. * data type(s)
  71. *
  72. * Return Codes:
  73. *
  74. * Standard PDU error codes.
  75. *
  76. * SNMP_ERRORSTATUS_NOERROR Successful get
  77. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  78. * mibtget.c v0.10
  79. *
  80. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  81. | hrPrinterStatus
  82. |
  83. | ACCESS SYNTAX
  84. | read-only INTEGER {other(1),unknown(2),idle(3),printing(4),warmup(5)}
  85. |
  86. | "The current status of this printer device. When in the idle(1), printing(2),
  87. | or warmup(3) state, the corresponding hrDeviceStatus should be running(2) or
  88. | warning(3). When in the unknown state, the corresponding hrDeviceStatus
  89. | should be unknown(1)."
  90. |
  91. | DISCUSSION:
  92. |
  93. | <POA-14> The actual status and error state of a hardware printer is deeply
  94. | buried with respect to the application level. Given that we can acquire
  95. | the name of the printer driver for a printer, some input on how best to
  96. | report the hardware status and error state would be appreciated.
  97. |
  98. | LIMITED RESOLUTION >>>>>>>>
  99. | <POA-14> We report logical printers as though they were hardware printers.
  100. | This results in certain "undercount" and "overcount" situations when using
  101. | Host MIB values for inventory purposes. For status purposes, the status
  102. | of the logical printers is returned.
  103. | LIMITED RESOLUTION >>>>>>>>
  104. |
  105. |============================================================================
  106. | 1.3.6.1.2.1.25.3.5.1.1.<instance>
  107. | | | | |
  108. | | | | *hrPrinterStatus
  109. | | | *hrPrinterEntry
  110. | | *hrPrinterTable
  111. | *-hrDevice
  112. */
  113. UINT
  114. GetHrPrinterStatus(
  115. OUT INThrPrinterStatus *outvalue ,
  116. IN Access_Credential *access ,
  117. IN InstanceName *instance )
  118. {
  119. ULONG index; /* As fetched from instance structure */
  120. CACHEROW *row; /* Row entry fetched from cache */
  121. /*
  122. | Grab the instance information
  123. */
  124. index = GET_INSTANCE(0);
  125. /*
  126. | Use it to find the right entry in the cache
  127. */
  128. if ((row = FindTableRow(index, &hrDevice_cache)) == NULL) {
  129. return SNMP_ERRORSTATUS_GENERR;
  130. }
  131. /*
  132. | Ok, here's the skinny: Just about all the status information that can
  133. | be acquired about a printer under NT is acquired by
  134. | "COMPUTE_hrPrinter_status()" that was written to service the need of
  135. | reporting general status for printer devices out of "hrDeviceStatus".
  136. |
  137. | Since we can't gather any more information reliably than this function
  138. | does, we simply call it and map the return codes it provides as values
  139. | for "hrDeviceStatus" into codes appropriate for this attribute variable.
  140. |
  141. */
  142. if (COMPUTE_hrPrinter_status(row, (UINT *) outvalue) != TRUE) {
  143. return SNMP_ERRORSTATUS_GENERR;
  144. }
  145. /* We get back:
  146. | "unknown" = 1 If we can't open the printer at all.
  147. |
  148. | "running" = 2 If we can open the printer and no status is
  149. | showing on it.
  150. | "warning" = 3 If we can open the printer but PAUSED or
  151. | PENDING_DELETION is showing on it.
  152. */
  153. switch (*outvalue) {
  154. case 1: // "unknown" for hrDeviceStatus
  155. *outvalue = 2; // goes to-> "unknown" for hrPrinterStatus
  156. break;
  157. case 2: // "running" for hrDeviceStatus
  158. case 3: // "warning" for hrDeviceStatus
  159. default:
  160. *outvalue = 1; // goes to-> "other" for hrPrinterStatus
  161. break;
  162. }
  163. return SNMP_ERRORSTATUS_NOERROR ;
  164. } /* end of GetHrPrinterStatus() */
  165. /*
  166. * GetHrPrinterDetectedErrorState
  167. * The error conditions as detected by the printer.
  168. *
  169. * Gets the value for HrPrinterDetectedErrorState.
  170. *
  171. * Arguments:
  172. *
  173. * outvalue address to return variable value
  174. * accesss Reserved for future security use
  175. * instance address of instance name as ordered native
  176. * data type(s)
  177. *
  178. * Return Codes:
  179. *
  180. * Standard PDU error codes.
  181. *
  182. * SNMP_ERRORSTATUS_NOERROR Successful get
  183. * SNMP_ERRORSTATUS_GENERR Catch-all failure code
  184. * mibtget.c v0.10
  185. *
  186. | =============== From WebEnable Design Spec Rev 3 04/11/97==================
  187. | hrPrinterDetectedErrorState
  188. |
  189. | ACCESS SYNTAX
  190. | read-only OCTET STRING
  191. |
  192. | "This object represents any error conditions detected by the printer. The
  193. | error conditions are encoded as bits in an octet string, with the following
  194. | definitions:
  195. |
  196. | Condition Bit # hrDeviceStatus
  197. |
  198. | lowPaper 0 warning(3)
  199. | noPaper 1 down(5)
  200. | lowToner 2 warning(3)
  201. | noToner 3 down(5)
  202. | doorOpen 4 down(5)
  203. | jammed 5 down(5)
  204. | offline 6 down(5)
  205. | serviceRequested 7 warning(3)
  206. |
  207. | If multiple conditions are currently detected and the hrDeviceStatus would not
  208. | otherwise be unknown(1) or testing(4), the hrDeviceStatus shall correspond to
  209. | the worst state of those indicated, where down(5) is worse than warning(3)
  210. | which is worse than running(2).
  211. |
  212. | Bits are numbered starting with the most significant bit of the first byte
  213. | being bit 0, the least significant bit of the first byte being bit 7, the most
  214. | significant bit of the second byte being bit 8, and so on. A one bit encodes
  215. | that the condition was detected, while a zero bit encodes that the condition
  216. | was not detected.
  217. |
  218. | This object is useful for alerting an operator to specific warning or error
  219. | conditions that may occur, especially those requiring human intervention."
  220. |
  221. | DISCUSSION:
  222. |
  223. | (See discussion above for "hrPrinterStatus").
  224. |
  225. |============================================================================
  226. | 1.3.6.1.2.1.25.3.5.1.2.<instance>
  227. | | | | |
  228. | | | | *hrPrinterDetectedErrorState
  229. | | | *hrPrinterEntry
  230. | | *hrPrinterTable
  231. | *-hrDevice
  232. */
  233. UINT
  234. GetHrPrinterDetectedErrorState(
  235. OUT OctetString *outvalue ,
  236. IN Access_Credential *access ,
  237. IN InstanceName *instance )
  238. {
  239. /*
  240. | The deal on this attribute is that under NT, you can barely tell
  241. | if the printer is on, unlike 95, where you can tell if it is on its
  242. | second bottle of toner for the day.
  243. |
  244. | Consequently we return a single all-bits zero octet regardless of
  245. | the instance value (which by now in the calling sequence of things
  246. | has been validated anyway).
  247. */
  248. outvalue->length = 1;
  249. outvalue->string = "\0";
  250. return SNMP_ERRORSTATUS_NOERROR ;
  251. } /* end of GetHrPrinterDetectedErrorState() */
  252. /*
  253. * HrPrinterEntryFindInstance
  254. *
  255. * This routine is used to verify that the specified instance is
  256. * valid.
  257. *
  258. * Arguments:
  259. *
  260. * FullOid Address for the full oid - group, variable,
  261. * and instance information
  262. * instance Address for instance specification as an oid
  263. *
  264. * Return Codes:
  265. *
  266. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  267. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  268. *
  269. */
  270. UINT
  271. HrPrinterEntryFindInstance( IN ObjectIdentifier *FullOid ,
  272. IN OUT ObjectIdentifier *instance )
  273. {
  274. UINT tmp_instance; /* Instance arc value */
  275. CACHEROW *row; /* Row entry fetched from cache */
  276. //
  277. // Developer instrumentation code to find appropriate instance goes here.
  278. // For non-tables, it is not necessary to modify this routine. However, if
  279. // there is any context that needs to be set, it can be done here.
  280. //
  281. if ( FullOid->idLength <= HRPRINTERENTRY_VAR_INDEX )
  282. // No instance was specified
  283. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  284. else if ( FullOid->idLength != HRPRINTERENTRY_VAR_INDEX + 1 )
  285. // Instance length is more than 1
  286. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  287. else
  288. // The only valid instance for a non-table are instance 0. If this
  289. // is a non-table, the following code validates the instances. If this
  290. // is a table, developer modification is necessary below.
  291. tmp_instance = FullOid->ids[ HRPRINTERENTRY_VAR_INDEX ] ;
  292. /*
  293. | For hrPrinterTable, the instance arc(s) is a single arc, and it must
  294. | correctly select an entry in the hrDeviceTable cache.
  295. |
  296. | Check that here.
  297. */
  298. if ( (row = FindTableRow(tmp_instance, &hrDevice_cache)) == NULL ) {
  299. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  300. }
  301. else
  302. {
  303. /*
  304. | The instance arc selects an hrDeviceTable row entry, but is that
  305. | entry actually for a device of type "Printer"?
  306. |
  307. | (We examine the last arc of the OID that specifies the device
  308. | type in the row entry selected by the instance arc).
  309. */
  310. if (row->attrib_list[HRDV_TYPE].u.unumber_value !=
  311. HRDV_TYPE_LASTARC_PRINTER) {
  312. return SNMP_ERRORSTATUS_NOSUCHNAME;
  313. }
  314. // the instance is valid. Create the instance portion of the OID
  315. // to be returned from this call.
  316. instance->ids[ 0 ] = tmp_instance ;
  317. instance->idLength = 1 ;
  318. }
  319. return SNMP_ERRORSTATUS_NOERROR ;
  320. } /* end of HrPrinterEntryFindInstance() */
  321. /*
  322. * HrPrinterEntryFindNextInstance
  323. *
  324. * This routine is called to get the next instance. If no instance
  325. * was passed than return the first instance (1).
  326. *
  327. * Arguments:
  328. *
  329. * FullOid Address for the full oid - group, variable,
  330. * and instance information
  331. * instance Address for instance specification as an oid
  332. *
  333. * Return Codes:
  334. *
  335. * SNMP_ERRORSTATUS_NOERROR Instance found and valid
  336. * SNMP_ERRORSTATUS_NOSUCHNAME Invalid instance
  337. *
  338. */
  339. UINT
  340. HrPrinterEntryFindNextInstance( IN ObjectIdentifier *FullOid ,
  341. IN OUT ObjectIdentifier *instance )
  342. {
  343. //
  344. // Developer supplied code to find the next instance of class goes here.
  345. // If this is a class with cardinality 1, no modification of this routine
  346. // is necessary unless additional context needs to be set.
  347. // If the FullOid does not specify an instance, then the only instance
  348. // of the class is returned. If this is a table, the first row of the
  349. // table is returned.
  350. //
  351. // If an instance is specified and this is a non-table class, then NOSUCHNAME
  352. // is returned so that correct MIB rollover processing occurs. If this is
  353. // a table, then the next instance is the one following the current instance.
  354. // If there are no more instances in the table, return NOSUCHNAME.
  355. //
  356. CACHEROW *row;
  357. ULONG tmp_instance;
  358. if ( FullOid->idLength <= HRPRINTERENTRY_VAR_INDEX )
  359. {
  360. /*
  361. | Too short: must return the instance arc that selects the first
  362. | entry in the table if there is one.
  363. */
  364. tmp_instance = 0;
  365. }
  366. else {
  367. /*
  368. | There is at least one instance arc. Even if it is the only arc
  369. | we use it as the "index" in a request for the "NEXT" one.
  370. */
  371. tmp_instance = FullOid->ids[ HRPRINTERENTRY_VAR_INDEX ] ;
  372. }
  373. /* Now go off and try to find the next instance in the table */
  374. if ((row = FindNextTableRow(tmp_instance, &hrDevice_cache)) == NULL) {
  375. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  376. }
  377. /*
  378. | The instance arc selects an hrDeviceTable row entry, but is that
  379. | entry actually for a device of type "Printer"?
  380. |
  381. | (We examine the last arc of the OID that specifies the device
  382. | type in the row entry selected by the instance arc).
  383. */
  384. do {
  385. if (row->attrib_list[HRDV_TYPE].u.unumber_value ==
  386. HRDV_TYPE_LASTARC_PRINTER) {
  387. /* Found an hrDeviceTable entry for the right device type */
  388. break;
  389. }
  390. /* Step to the next row in the table */
  391. row = GetNextTableRow( row );
  392. }
  393. while ( row != NULL );
  394. /* If we found a proper device-type row . . . */
  395. if ( row != NULL) {
  396. instance->ids[ 0 ] = row->index ;
  397. instance->idLength = 1 ;
  398. }
  399. else {
  400. /*
  401. | Fell off the end of the hrDeviceTable without finding a row
  402. | entry that had the right device type.
  403. */
  404. return SNMP_ERRORSTATUS_NOSUCHNAME ;
  405. }
  406. return SNMP_ERRORSTATUS_NOERROR ;
  407. } /* end of HrPrinterEntryFindNextInstance() */
  408. /*
  409. * HrPrinterEntryConvertInstance
  410. *
  411. * This routine is used to convert the object id specification of an
  412. * instance into an ordered native representation. The object id format
  413. * is that object identifier that is returned from the Find Instance
  414. * or Find Next Instance routines. It is NOT the full object identifier
  415. * that contains the group and variable object ids as well. The native
  416. * representation is an argc/argv-like structure that contains the
  417. * ordered variables that define the instance. This is specified by
  418. * the MIB's INDEX clause. See RFC 1212 for information about the INDEX
  419. * clause.
  420. *
  421. *
  422. * Arguments:
  423. *
  424. * oid_spec Address of the object id instance specification
  425. * native_spec Address to return the ordered native instance
  426. * specification
  427. *
  428. * Return Codes:
  429. *
  430. * SUCCESS Conversion complete successfully
  431. * FAILURE Unable to convert object id into native format
  432. *
  433. */
  434. UINT
  435. HrPrinterEntryConvertInstance( IN ObjectIdentifier *oid_spec ,
  436. IN OUT InstanceName *native_spec )
  437. {
  438. static char *array; /* The address of this (char *) is passed back */
  439. /* as though it were an array of length 1 of these */
  440. /* types. */
  441. static ULONG inst; /* The address of this ULONG is passed back */
  442. /* (Obviously, no "free()" action is needed) */
  443. /* We only expect the one arc in "oid_spec" */
  444. inst = oid_spec->ids[0];
  445. array = (char *) &inst;
  446. native_spec->count = 1;
  447. native_spec->array = &array;
  448. return SUCCESS ;
  449. } /* end of HrPrinterEntryConvertInstance() */
  450. /*
  451. * HrPrinterEntryFreeInstance
  452. *
  453. * This routine is used to free an ordered native representation of an
  454. * instance name.
  455. *
  456. * Arguments:
  457. *
  458. * instance Address to return the ordered native instance
  459. * specification
  460. *
  461. * Return Codes:
  462. *
  463. *
  464. */
  465. void
  466. HrPrinterEntryFreeInstance( IN OUT InstanceName *instance )
  467. {
  468. /* No action needed for hrPrinter Table */
  469. } /* end of HrPrinterEntryFreeInstance() */
  470. /*
  471. | End of Generated Code
  472. */
  473. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  474. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  475. /* Gen_HrPrinter_Cache - Generate a initial cache for HrDevice PRINTER Table */
  476. BOOL
  477. Gen_HrPrinter_Cache(
  478. ULONG type_arc
  479. )
  480. /*
  481. | EXPLICIT INPUTS:
  482. |
  483. | "type_arc" is the number "n" to be used as the last arc in the
  484. | device-type OID:
  485. |
  486. | 1.3.6.1.2.1.25.3.1.n
  487. | | | |
  488. | | | * Identifying arc for type
  489. | | *-hrDeviceTypes (OIDs specifying device types)
  490. | *-hrDevice
  491. |
  492. | for devices created by this cache-population routine.
  493. |
  494. | IMPLICIT INPUTS:
  495. |
  496. | None.
  497. |
  498. | OUTPUTS:
  499. |
  500. | On Success:
  501. | Function returns TRUE indicating that the HrDevice cache has been fully
  502. | populated with all rows required for Printer devices.
  503. |
  504. | On any Failure:
  505. | Function returns FALSE (indicating "not enough storage" or other
  506. | internal logic error).
  507. |
  508. | THE BIG PICTURE:
  509. |
  510. | At subagent startup time, the cache for each table in the MIB is
  511. | populated with rows for each row in the table. This function is
  512. | invoked by the start-up code in "Gen_HrDevice_Cache()" to
  513. | populate the cache for the HrDevice table with printer-specific
  514. | entries.
  515. |
  516. | OTHER THINGS TO KNOW:
  517. |
  518. | Since all the attributes in the HrPrinter "sub" table are computed
  519. | upon request (based on cached information in a selected row in the
  520. | HrDevice table) there is no need to build a cache specifically for
  521. | this sub-table. (This routine is loading the HrDevice cache despite
  522. | it's name). --------
  523. |
  524. | This function holds a convention with the GET routines earlier in
  525. | this module that the "HIDDEN_CTX" attribute for printers contains
  526. | a string that can be used in OpenPrinter to get a handle to that
  527. | printer.
  528. |============================================================================
  529. | 1.3.6.1.2.1.25.3.5.1...
  530. | | | |
  531. | | | *hrPrinterEntry
  532. | | *hrPrinterTable
  533. | *-hrDevice
  534. |
  535. */
  536. {
  537. CHAR temp[8]; /* Temporary buffer for first call */
  538. DWORD PI_request_len; /* Printer Info: Storage actually needed */
  539. DWORD PI_current_len; /* Printer Info: Storage used on 2nd call */
  540. DWORD PI_count; /* Count of Printer Infos returned */
  541. UINT i; /* Handy-Dandy loop index */
  542. PRINTER_INFO_4
  543. *PrinterInfo; /* --> allocated storage for drive strings */
  544. /*
  545. | We're going to call EnumPrinters() twice, once to get the proper
  546. | buffer size, and the second time to actually get the printer info.
  547. */
  548. EnumPrinters(PRINTER_ENUM_LOCAL, // Flags
  549. NULL, // Name (ignored)
  550. 4, // Level
  551. temp, // Buffer
  552. 1, // "Too Small" Buffer size
  553. &PI_request_len, // Required length... comes back.
  554. &PI_count
  555. );
  556. /*
  557. | Grab enough storage for the enumeration structures
  558. */
  559. if ( (PrinterInfo = malloc(PI_request_len)) == NULL) {
  560. /* Storage Request failed altogether, can't initialize */
  561. return ( FALSE );
  562. }
  563. /* Now get the real stuff */
  564. if (!EnumPrinters(PRINTER_ENUM_LOCAL, // Flags
  565. NULL, // Name (ignored)
  566. 4, // Level
  567. (unsigned char *) PrinterInfo, // Buffer to receive enumeration
  568. PI_request_len, // Actual buffer size
  569. &PI_request_len, // Required length... comes back.
  570. &PI_count
  571. )) {
  572. /* Failed for some reason */
  573. free( PrinterInfo );
  574. return ( FALSE );
  575. }
  576. /*
  577. | Now swing down the list, and for every LOCAL printer,
  578. |
  579. | + Fetch the description
  580. | + Make an hrDevice table row entry with the printer name & description
  581. */
  582. for (i = 0; i < PI_count; i += 1) {
  583. /* If it is a Local printer ... */
  584. if (PrinterInfo[i].Attributes & PRINTER_ATTRIBUTE_LOCAL) {
  585. HANDLE hprinter; /* Handle to a printer */
  586. /* Open it to get a handle */
  587. if (OpenPrinter(PrinterInfo[i].pPrinterName, // Printer Name
  588. &hprinter, // Receive handle here
  589. NULL // Security
  590. ) == TRUE ) {
  591. PRINTER_INFO_2 *p2;
  592. DWORD P2_request_len; /* Bytes-needed by GetPrinter */
  593. /*
  594. | Printer is Open, get a PRINTER_INFO_2 "slug-o-data"
  595. |
  596. | 1st call: Fails, but gets buffer size needed.
  597. */
  598. GetPrinter(hprinter, // printer handle
  599. 2, // Level 2
  600. temp, // Buffer for INFO_2
  601. 1, // Buffer-too-small
  602. &P2_request_len // What we really need
  603. );
  604. /*
  605. | Grab enough storage for the PRINTER_INFO_2 structure
  606. */
  607. if ( (p2 = malloc(P2_request_len)) == NULL) {
  608. /* Storage Request failed altogether, can't initialize */
  609. free( PrinterInfo );
  610. ClosePrinter( hprinter );
  611. return ( FALSE );
  612. }
  613. /*
  614. | 2nd call: Should succeed.
  615. */
  616. if (GetPrinter(hprinter, // printer handle
  617. 2, // Level 2
  618. (unsigned char *) p2, // Buffer for INFO_2
  619. P2_request_len, // Buffer-just-right
  620. &P2_request_len // What we really need
  621. ) == TRUE) {
  622. /* Add a row to HrDevice Table
  623. |
  624. | We're using the printer-driver name as a "Poor Man's"
  625. | description: the driver "names" are quite descriptive with
  626. | version numbers yet!.
  627. |
  628. | The Hidden Context is the name needed to open the printer
  629. | to gain information about its status.
  630. */
  631. if (AddHrDeviceRow(type_arc, // DeviceType OID Last-Arc
  632. p2->pDriverName, // Used as description
  633. PrinterInfo[i].pPrinterName, // Hidden Ctx
  634. CA_STRING // Hidden Ctx type
  635. ) == NULL ) {
  636. /* Failure at a lower level: drop everything */
  637. free( p2 );
  638. free( PrinterInfo );
  639. ClosePrinter( hprinter );
  640. return ( FALSE );
  641. }
  642. }
  643. /* Close up shop on this printer*/
  644. free( p2 );
  645. ClosePrinter( hprinter );
  646. }
  647. }
  648. }
  649. free( PrinterInfo );
  650. return ( TRUE );
  651. }
  652. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  653. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  654. /* COMPUTE_hrPrinter_errors - Compute "hrDeviceErrors" for a Printer device */
  655. BOOL
  656. COMPUTE_hrPrinter_errors(
  657. CACHEROW *row,
  658. UINT *outvalue
  659. )
  660. /*
  661. | EXPLICIT INPUTS:
  662. |
  663. | "row" points to the hrDevice cache row for the printer whose error
  664. | count is to be returned.
  665. |
  666. | Attribute "HIDDEN_CTX" has a string value that is the name of the
  667. | printer by convention with "Gen_HrPrinter_Cache()" above.
  668. |
  669. | "outvalue" is a pointer to an integer to receive the error count.
  670. |
  671. | IMPLICIT INPUTS:
  672. |
  673. | None.
  674. |
  675. | OUTPUTS:
  676. |
  677. | On Success:
  678. | Function returns TRUE and an error count for the specified printer.
  679. |
  680. | On any Failure:
  681. | Function returns FALSE.
  682. |
  683. | THE BIG PICTURE:
  684. |
  685. | For an hrDevice attribute whose value is "computed", at the time of
  686. | the request to see it is received, we dispatch to a "COMPUTE_" function
  687. | to get the value. This is such a routine for printers.
  688. |
  689. | OTHER THINGS TO KNOW:
  690. |
  691. | This function holds a convention with the Gen_cache routines earlier in
  692. | this module that the "HIDDEN_CTX" attribute for printers contains
  693. | a string that can be used in OpenPrinter to get a handle to that
  694. | printer.
  695. */
  696. {
  697. /*
  698. | No way to get any error counts under NT
  699. */
  700. *outvalue = 0;
  701. return ( TRUE );
  702. }
  703. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  704. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  705. /* COMPUTE_hrPrinter_status - Compute "hrDeviceStatus" for a Printer device */
  706. BOOL
  707. COMPUTE_hrPrinter_status(
  708. CACHEROW *row,
  709. UINT *outvalue
  710. )
  711. /*
  712. | EXPLICIT INPUTS:
  713. |
  714. | "row" points to the hrDevice cache row for the printer whose status
  715. | is to be returned.
  716. |
  717. | Attribute "HIDDEN_CTX" has a string value that is the name of the
  718. | printer by convention with "Gen_HrPrinter_Cache()" above.
  719. |
  720. | "outvalue" is a pointer to an integer to receive the status.
  721. |
  722. | IMPLICIT INPUTS:
  723. |
  724. | None.
  725. |
  726. | OUTPUTS:
  727. |
  728. | On Success:
  729. | Function returns TRUE and a status for the specified printer:
  730. |
  731. | "unknown" = 1 If we can't open the printer at all.
  732. |
  733. | "running" = 2 If we can open the printer and no status is
  734. | showing on it.
  735. | "warning" = 3 If we can open the printer but PAUSED or
  736. | PENDING_DELETION is showing on it.
  737. |
  738. |
  739. | On any Failure:
  740. | Function returns FALSE.
  741. |
  742. | THE BIG PICTURE:
  743. |
  744. | For an hrDevice attribute whose value is "computed", at the time of
  745. | the request to see it is received, we dispatch to a "COMPUTE_" function
  746. | to get the value. This is such a routine for printers.
  747. |
  748. | OTHER THINGS TO KNOW:
  749. |
  750. | This function holds a convention with the Gen_cache routines earlier in
  751. | this module that the "HIDDEN_CTX" attribute for printers contains
  752. | a string that can be used in OpenPrinter to get a handle to that
  753. | printer.
  754. */
  755. {
  756. CHAR temp[8]; /* Temporary buffer for first call */
  757. HANDLE hprinter; /* Handle to a printer */
  758. /* Open Printer whose name is in "Hidden Context" to get a handle */
  759. if (OpenPrinter(row->attrib_list[HIDDEN_CTX].u.string_value, // Printer Name
  760. &hprinter, // Receive handle here
  761. NULL // Security
  762. ) == TRUE ) {
  763. PRINTER_INFO_2 *p2;
  764. DWORD P2_request_len; /* Bytes-needed by GetPrinter */
  765. /*
  766. | Printer is Open, get a PRINTER_INFO_2 "slug-o-data"
  767. |
  768. | 1st call: Fails, get buffer size needed.
  769. */
  770. GetPrinter(hprinter, // printer handle
  771. 2, // Level 2
  772. temp, // Buffer for INFO_2
  773. 1, // Buffer-too-small
  774. &P2_request_len // What we really need
  775. );
  776. /*
  777. | Grab enough storage for the PRINTER_INFO_2 structure
  778. */
  779. if ( (p2 = malloc(P2_request_len)) == NULL) {
  780. /* Storage Request failed altogether */
  781. ClosePrinter( hprinter );
  782. return ( FALSE );
  783. }
  784. /*
  785. | 2nd call: Should succeed.
  786. */
  787. if (GetPrinter(hprinter, // printer handle
  788. 2, // Level 2
  789. (unsigned char *) p2, // Buffer for INFO_2
  790. P2_request_len, // Buffer-just-right
  791. &P2_request_len // What we really need
  792. ) == TRUE) {
  793. /*
  794. | As of this writing, only two status values are available
  795. | under NT:
  796. |
  797. | PRINTER_STATUS_PAUSED
  798. | PRINTER_STATUS_PENDING_DELETION
  799. |
  800. | Basically, if either of these is TRUE, we'll signal "warning".
  801. | If neither are TRUE, we'll signal "running" (on the basis that
  802. | we've managed to open the printer OK and it shows no status).
  803. */
  804. if ( (p2->Status & PRINTER_STATUS_PAUSED)
  805. || (p2->Status & PRINTER_STATUS_PENDING_DELETION)) {
  806. *outvalue = 3; // "warning"
  807. }
  808. else {
  809. *outvalue = 2; // "running"
  810. }
  811. }
  812. /* Free up and return */
  813. ClosePrinter( hprinter );
  814. free( p2 );
  815. }
  816. else {
  817. *outvalue = 1; // "unknown"
  818. }
  819. return ( TRUE );
  820. }