Despite efforts to achieve a truly paperless office, all users still require access to print devices. Unfortunately, these mechanical marvels seem to host the largest number of service calls, perhaps because of the high number of moving parts , or simply because of the number of users sharing the device. Although ADSI certainly can't help when the toner is low or a paper jam occurs, it is well suited to help you manage both the print queue and print jobs associated with a network printing device.
In most well-organized enterprises , one or several servers are tasked with the job of hosting print queues. Even in the most well-managed enterprise, someone will depart from the established policies and create a print queue somewhere it does not belong.
To discover such departures from standards by showing all print queues for all machines in a given domain, combine the print queue enumeration example shown in this section with the container enumeration functions for computer accounts.
Note
Be prepared: This can take some time in large resource domains.
If you already know the name of a print server on the network, use the following Visual Basic code to find the names of all queues hosted on the machine:
Dim ComputerName As String Dim ComputerDomain As String Dim Container as IADsContainer Dim PrintQueue as IADsPrintQueue ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " Set Container = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName) Container.Filter = Array("PrintQueue") For Each PrintQueue In Container Debug.Print PrintQueue.Name Next
You could enumerate an entire machine and use a conditional to find a specific queue, assuming the exact name of the queue is known. A much more appropriate method, however, would be simply to bind directly to the queue object itself.
To do this, use the following Visual Basic code:
Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName as String Dim PrintQueue as IADsPrintQueue ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " PrintQueueName = " Target_Print_Queue " Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" & PrintQueueName&",printqueue")
Using the IADsPrintQueue interface, you can query the properties of an existing print queue (see Table 7.1).
Property | Description | Return Datatype |
---|---|---|
BannerPage | Used to get/set the path to the file used to separate print jobs. | String |
Datatype | Specifies the type of data that can be processed by the queue. Usually this should be "RAW." | String |
DefaultJobPriority | The default priority assigned to new print jobs. | Integer |
Description | The free-text comment field associated with the queue. | String |
Location | A free-text field used to describe the physical location of the printer. | String |
Model | The name of the print driver used for this queue. | String |
Name | The programmatic name of the printer. | String |
PrintDevices | Defines the paths to other printers in the printer pool. | Variant |
PrinterPath | Specifies the path to a printer. | String |
PrintProcessor | The print processor associated with this queue. Usually set to "winprint." | String |
Priority | The priority associated with the print queue. An administrator can create a high- priority print queue for small print jobs and another, low-priority, off-hours-only queue for printing large documents and booklets. | Integer |
StartTime | Establishes the lower bound of the valid time for use with this queue. | Date |
UntilTime | Establishes the upper bound of the valid time for use with this queue. | Date |
You can examine each of the properties in the preceding table (except PrintDevices ) by using syntax similar to the following:
Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName as String Dim PrintQueue as IADsPrintQueue Dim RetVal as String ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " PrintQueueName = " Target_Print_Queue " Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" & PrintQueueName) RetVal = PrintQueue.Model Debug.Print RetVal
Warning
When dimensioning the return value (RetVal in this example), be sure to specify the proper datatype associated with the property to avoid type mismatch errors.
To manipulate the PrintDevices property (which returns a variant array of strings), use the following Visual Basic code:
Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName as String Dim PrintQueue as IADsPrintQueue Dim Item as Variant ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " PrintQueueName = " Target_Print_Queue " Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) If IsArray(PrintQueue.PrintDevices) Then For Each Item In PrintQueue.PrintDevices Debug.Print Item Next Else Debug.Print PrintQueue.PrintDevices End If
The IADsPrintQueueOperations interface allows the administrator to query the status of a queue, pause and resume operation of a queue, and examine the current list of print jobs in a queue. This can be incredibly useful for building applications that will allow inexperienced help desk staff to diagnose print server issues using a Web interface or custom application.
Using the IADsPrintQueueOperations interface, you can query the current status of the queue. By implementing the following Visual Basic code, you can return the value of the IADsPrintQueueOperations Status method to find the current status of a print queue:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim RetVal As Long ComputerDomain = " Target_Computer_Domain " ComputerName = " Target_Computer_Name " PrintQueueName = " Target_Print_Queue " Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) RetVal = PrintQueue.Status Debug.Print RetVal
To make it easier to decipher the status return codes, you may want to include a list of constants (using Table 7.2 as a guide) in your code module.
Constant | Value |
---|---|
ADS_PRINTER_READY | 0x0 |
ADS_PRINTER_PAUSED | 0x1 |
ADS_PRINTER_PENDING_DELETION | 0x2 |
ADS_PRINTER_ERROR | 0x3 |
ADS_PRINTER_PAPER_JAM | 0x4 |
ADS_PRINTER_PAPER_OUT | 0x5 |
ADS_PRINTER_MANUAL_FEED | 0x6 |
ADS_PRINTER_PAPER_PROBLEM | 0x7 |
ADS_PRINTER_OFFLINE | 0x8 |
ADS_PRINTER_IO_ACTIVE | 0x100 |
ADS_PRINTER_BUSY | 0x200 |
ADS_PRINTER_PRINTING | 0x400 |
ADS_PRINTER_OUTPUT_BIN_FULL | 0x800 |
ADS_PRINTER_NOT_AVAILABLE | 0x1000 |
ADS_PRINTER_WAITING | 0x2000 |
ADS_PRINTER_PROCESSING | 0x4000 |
ADS_PRINTER_INITIALIZING | 0x8000 |
ADS_PRINTER_WARMING_UP | 0x10000 |
ADS_PRINTER_TONER_LOW | 0x20000 |
ADS_PRINTER_NO_TONER | 0x40000 |
ADS_PRINTER_PAGE_PUNT | 0x80000 |
ADS_PRINTER_USER_INTERVENTION | 0x100000 |
ADS_PRINTER_OUT_OF_MEMORY | 0x200000 |
ADS_PRINTER_DOOR_OPEN | 0x400000 |
ADS_PRINTER_SERVER_UNKNOWN | 0x800000 |
ADS_PRINTER_POWER_SAVE | 0x1000000 |
There may be occasions when you want to pause the print queue to perform service on the printer, or perhaps to build up a few jobs in the queue to explore programmatic print job management.
To pause a print queue, call the Pause method of the IADsPrintQueueOperations interface after binding the queue. Use the following Visual Basic code as a guide to pause a queue:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim RetVal As Long ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) PrintQueue.Pause
Note
The Pause and Resume methods take a few moments to take effect. Do not make a call to the IADsPrintQueueOperations Status property immediately following one of these actions, for the property may not yet reflect the change.
To resume the print queue after it has been in a paused state, use the following code to bring the queue back to normal operations:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim RetVal As Long ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) PrintQueue.Resume
Using the Windows NT 4.0 GUI, you can view print queues and jobs by double-clicking the desired printer in the Printers folder, as shown in Figure 7.6. By using a For Each Next loop to enumerate the contents of the variant array passed back from the PrintJobs method of the IADsPrintQueueOperations interface, you can view contents and properties of individual jobs contained within the queue programmatically.
Use the following Visual Basic code to display the programmatic ID, document name, document owner, and total page count of print jobs in a given queue:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim PrintJob as IADsPrintJob ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) For Each PrintJob in PrintQueue.PrintJobs Debug.Print PrintJob.Name&" "&PrintJob.Description&" "&PrintJob.User &" "&PrintJob.TotalPages Next
In addition to the programmatic identifier, document name, document owner, and total pages submitted that you examined in the previous example, there are many more properties you can examine for a particular print job. Use the Table 7.3 as a guide.
Method/Property | Description | Read Only? | Return Datatype |
---|---|---|---|
Description | The title of the document | No | String |
HostPrintQueue | The ADsPath of the host queue | Yes | String |
Notify | The userid of the user to notify when printing has completed | No | String |
Priority | The priority of the job in the queue | No | Integer |
Size | The size (in bytes) of the submitted job | Yes | Long |
StartTime | The earliest time for the job to be printed | No | Date |
TimeSubmitted | The time the job was submitted to the queue | Yes | Date |
TotalPages | The total number of pages to be printed | Yes | Long |
UntilTime | The latest time for the job to be printed | No | Date |
User | The owner of the print job | Yes | String |
You can simply use a Debug.Print statement (use the code from the preceding "Querying Print Queue Properties Using Visual Basic" section as a guide) to list all of these properties on a single line, or you can store each one in a variable of the appropriate datatype.
You can actually manipulate the non-read-only properties using the IADsPrintJob interface.
Consider the following Visual Basic code that will raise the priority of any job in the queue bearing a specific username to a priority value of 99:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim PrintJob as IADsPrintJob Dim UserToPrioritize as String ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" UserToPrioritize = "User_To_Elevate_Priority" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) For Each PrintJob in PrintQueue.PrintJobs If PrintJob.User = UserToPrioritize Then PrintJob.Priority = 99 PrintJob.SetInfo End If Next
Additional Properties Provided by the IADsPrintJobOperations Interface
There are many properties exposed by the IADsPrintJob interface. However, you cannot discover any real-time information about the current status of a print job within the queue, such as position, time elapsed since the job began printing, or the number of pages that have already been printed. To find out this information, you can dimension a variable of type IADsPrintJobOperations to discover these extended, time-sensitive properties.
These properties can be accessed just like those of the IADsPrintJob interface ”by using a debug statement or storing the returned values of each query in an appropriately dimensioned variable .
To help determine the proper usage of these properties, use Table 7.4 .
Method/Property | Description | Read Only? | Return Datatype |
---|---|---|---|
PagesPrinted | The number of pages of the job that have already been printed | Yes | Long |
Position | The position of the currently selected job in the queue | No | Long |
Status | The current status of the job | Yes | Paused (1) |
Error (2) | |||
Deleting (4) | |||
Printing (10) | |||
Offline (20) | |||
PaperOut (40) | |||
Printed (80) | |||
Deleted (100) | |||
TimeElapsed | The time (in seconds) that the job has been being serviced by the printer | Yes | Long |
Occasionally, there is a need to delete a print job that has been placed in the print queue. ADSI can perform the task almost effortlessly, using the IADsCollection interface. This interface stores the contents of the collection returned by the PrintJobs method of the IADsPrintQueueOperations interface. With the print jobs stored in the collection, you can remove specific jobs.
To perform this task, you must first know the programmatic ID of the job to delete. This is an integer or long integer value that uniquely identifies the document to be printed in the queue. To find the programmatic ID of the job, find it from the Name property of any object dimensioned of type IADsPrintJob.
Consider the following Visual Basic code that will remove all print jobs submitted by a particular user:
Dim PrintQueue As IADsPrintQueueOperations Dim PrintJob As IADsPrintJob Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim Collection As IADsCollection Dim UserToRemove as String ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" UserToRemove = "User_To_Remove_From_Queue" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) Set Collection = PrintQueue.PrintJobs For Each PrintJob In PrintQueue.PrintJobs If PrintJob.User = UserToRemove Then Collection.Remove (CStr(PrintJob.Name)) End If Next
There are two approaches to removing all entries from a print queue. You can use the code from the previous section without the conditional to limit it to just a single user, or you can simply call the Purge method of the IADsPrintQueueOperations interface. In general, enumeration functions are expensive in terms of system resources, so the Purge method is likely to be a better choice if you want to indiscriminately remove all jobs from a queue. Additionally, it is important to note that the PrintJobs method of the IADsPrintQueue interface takes a snapshot of the current jobs in the queue. As such, it may be possible for the jobs to be processed during the course of processing, causing binding errors. These errors are also eliminated by the Purge method.
Use the following Visual Basic code segment to remove all entries from a specific print queue:
Dim PrintQueue As IADsPrintQueueOperations Dim ComputerName As String Dim ComputerDomain As String Dim PrintQueueName As String Dim RetVal As Long ComputerDomain = "Target_Computer_Domain" ComputerName = "Target_Computer_Name" PrintQueueName = "Target_Print_Queue" Set PrintQueue = GetObject("WinNT://"&ComputerDomain&"/"&ComputerName&"/" &PrintQueueName) PrintQueue.Purge
Top |