Microsoft KB Archive/821769

= How to call the EnumJobs function from a Visual Basic .NET application =

Article ID: 821769

Article Last Modified on 5/16/2007

-

APPLIES TO


 * Microsoft Visual Basic .NET 2003 Standard Edition
 * Microsoft Visual Basic .NET 2002 Standard Edition

-





SUMMARY
''The EnumJobs function is available in the Winspool.drv print spool interface. You can use the EnumJobs function to retrieve the status of the jobs that are queued in a local print queue. The EnumJobs function enumerates the number of jobs, the job identification, the job status, and other parameters based on your requirements.''

 

''When you try to print any document, the print job is queued in the local print queue until the printer performs that job. The port monitor communicates with the printer to obtain information about a print job and then communicates the information to the local print queue. Therefore, you can monitor the local print queue to retrieve the status of your print job.''

 

''The local print queue accepts any number of jobs, even if the printer hardware is in an error state. Therefore, the Ready state of the print queue does not determine whether the job will print. Many statuses are available to report. However, many of them are not supported. The printer hardware and the port monitor determine the status that appears.''





IN THIS TASK

 * INTRODUCTION
 * Technical description
 * Step-by-step sample
 * Troubleshooting
 * REFERENCES



INTRODUCTION
This step-by-step article describes how to use Microsoft Windows API functions in Microsoft Visual Basic .NET to determine the printer status or the print job status programmatically. Although an application does not typically have to examine the status of a printer before the printer prints, it may be useful to determine the status of a printer or a print job programmatically.

back to the top

Technical description
The following information will help you use the sample application to obtain information about your printer status:
 * The term printer refers to a hardware device, a queue, a driver, or a port. Here, the term printer status refers to the status of a local print queue.
 * The sample code in the &quot;Step-by-step sample&quot; section returns the status that the operating system reports. This is the same status that the spooler reports. You can verify this status by monitoring the local print queue. The application continuously monitors the printer status.

To view the local print queue on a computer that is running the Microsoft Windows XP operating system, follow these steps:
 * Click Start, point to Settings, and then click Printers and Faxes.
 * In the Printers and Faxes window, double-click the icon for the printer whose queue you want to view.
 * You cannot communicate directly with the physical printer. We recommend that you do not do this because the operating system controls access to the hardware. The &quot;Step-by-step sample&quot; section examines the local print queue that obtains the information from the port monitor.
 * The port monitor communicates with the physical device. The sample code in the &quot;Step-by-step sample&quot; section reports the printer status and the job statuses.
 * The queue is considered to be in a Ready state because it can accept jobs, even if the hardware is in an error state. For example, if the last job that printed used the last sheet of paper, the operating system cannot determine that the printer is out of paper until the system tries to print again.
 * Although many statuses can be reported, many statuses are not supported in practice. The printer hardware and the port monitor determine the status to report. For example, if the printer is out of paper and is offline, the status may be reported as Printing because that is what the job is trying to do. Therefore, regardless of whether a local print queue displays the Ready status, the print job may not be completed successfully.
 * The sample code in the &quot;Step-by-step sample&quot; section examines only the local print queue. This information may be sufficient for most applications. However, when you connect to remote printers, the process to obtain sufficient information may become complex. You may have a chain of print queues, and the port for the local print queue may be another queue.
 * You may also use printer pooling. In printer pooling, multiple printers work from a common super queue. When the architecture becomes more complex, the code to retrieve a meaningful status also becomes more complex, and the usefulness of the status is reduced.

back to the top

Step-by-step sample
 Start Microsoft Visual Studio .NET. On the File menu, point to New, and then click Project. The New Project dialog box appears. Under Project Types, click Visual Basic Projects.</li> Under Templates, click Windows Application.</li> In the Name box, type PrinterStatus, and then click OK. By default, a form that is named Form1 is created.</li> On the Project menu, click Add Module. The Add New Item - PrinterStatus dialog box appears.</li> Under Templates, click Module, and then click Open. By default, a file that is named Module1.vb is created.</li>  In the Module1.vb file, replace the existing code with the following sample code. Option Explicit On

Imports System.Drawing.Printing.PrinterSettings Imports System.Runtime.InteropServices

Module Module1 Public Class WINAPI

Declare Auto Function GetPrinter Lib &quot;winspool.drv&quot; (ByVal hPrinter As _       IntPtr, ByVal Level As Integer, ByRef pPrinter As Byte, ByVal cbBuf _        As Integer, ByRef pcbNeeded As Integer) As Boolean

Declare Auto Function lstrcpy Lib &quot;Kernel32.Lib&quot; Alias &quot;lstrcpyA&quot; _ (<OutAttribute, MarshalAs(UnmanagedType.LPStr)> ByVal lpString1 As String, _       <MarshalAs(UnmanagedType.LPStr)> ByVal lpString2 As String) As Long

Declare Auto Function ClosePrinter Lib &quot;winspool.drv&quot; Alias &quot;ClosePrinter&quot; (ByVal hPrinter As IntPtr) As Long

Public Declare Function EnumJobs Lib &quot;winspool.drv&quot; Alias &quot;EnumJobsA&quot; _ (ByVal hPrinter As IntPtr, _       ByVal FirstJob As Int32, _        ByVal NoJobs As Int32, _        ByVal Level As Int32, _        ByVal pJob As Byte, _        ByVal cdBuf As Int32, _        ByRef pcbNeeded As Int32, _        ByRef pcReturned As Int32) _ As Long

Declare Function OpenPrinter Lib &quot;winspool.drv&quot; Alias &quot;OpenPrinterA&quot; (ByVal pPrinterName As String, _       ByRef phPrinter As IntPtr, ByVal pDefault As PRINTER_DEFAULTS) As Long End Class

'Constants for the PRINTER_DEFAULTS structure Public Const PRINTER_ACCESS_USE = &H8 Public Const PRINTER_ACCESS_ADMINISTER = &H4

'Constants for the DEVMODE structure Public Const CCHDEVICENAME = 32 Public Const CCHFORMNAME = 32 Public API As New WINAPI <StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Structure SYSTEMTIME Public wYear As Short Public wMonth As Short Public wDayOfWeek As Short Public wDay As Short Public wHour As Short Public wMinute As Short Public wSecond As Short Public wMilliseconds As Short End Structure

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Structure JOB_INFO_2 Public PrinterJobId As Integer Public pPrinterName As Integer Public PrinterName As Integer Public PrinterUserName As Integer Public PrinterDocument As Integer Public PrinterNotifyName As Integer Public PrinterDatatype As Integer Public PrintProcessor As Integer Public PrinterParameters As Integer Public PrinterDriverName As Integer Public PrinterDevMode As Integer Public PrinterStatus As Integer Public PrinterSecurityDescriptor As Integer Public pStatus As Integer Public PrinterPriority As Integer Public Position As Integer Public StartTime As Integer Public UntilTime As Integer Public TotalPages As Integer Public Size As Integer Public Submitted As SYSTEMTIME Public time As Integer Public PagesPrinted As Integer End Structure

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> Structure PRINTER_INFO_2 Public pServerName As Integer Public pPrinterName As Integer Public pShareName As Integer Public pPortName As Integer Public pDriverName As Integer Public pComment As Integer Public pLocation As Integer Public pDevMode As Integer Public pSepFile As Integer Public pPrintProcessor As Integer Public pDatatype As Integer Public pParameters As Integer Public pSecurityDescriptor As Integer Public Attributes As Integer Public Priority As Integer Public DefaultPriority As Integer Public StartTime As Integer Public UntilTime As Integer Public Status As Integer Public cJobs As Integer Public AveragePPM As Integer End Structure

Public Function Pointer_to_String(ByVal Add As Long) As String Dim Temp_var As String Temp_var = New String(CChar(&quot;&quot;), 512) Dim x As Long x = API.lstrcpy(Temp_var, Add) If (InStr(1, Temp_var, Chr(0)) = 0) Then Pointer_to_String = &quot;&quot; Else Pointer_to_String = Left(Temp_var, InStr(1, Temp_var, Chr(0)) - 1) End If   End Function

Public Function DatatoDeserial(ByVal datas As Byte, ByVal type_to_change As Type, _       ByVal NumJub As Long) As Object 'Returns the size of the JOB_INFO_2 structure Dim Data_to_Size As Long = Marshal.SizeOf(type_to_change) If Data_to_Size > datas.Length Then Return Nothing End If

Dim buffer As IntPtr = Marshal.AllocHGlobal(Data_to_Size) Dim startindex As Long Dim i As Integer For i = 0 To NumJub - 1 If i = 0 Then startindex = 0 Else startindex = startindex + Data_to_Size End If       Next 'Copy data from the datas array to the unmanaged memory pointer. Marshal.Copy(datas, startindex, buffer, Data_to_Size)

'Marshal data from the buffer pointer to a managed object. Dim result_obj As Object = Marshal.PtrToStructure(buffer, type_to_change) 'Free the memory that is allocated from the unmanaged memory. Marshal.FreeHGlobal(buffer) Return result_obj End Function

<StructLayout(LayoutKind.Sequential, CharSet:=CharSet.Auto)> _ Structure PRINTER_DEFAULTS Public pDatatype As String Public pDevMode As Long Public DesiredAccess As Long End Structure

'Define the printer status constants. Public Const ERROR_INSUFFICIENT_BUFFER = 122 Public Const PRINTER_STATUS_BUSY = &H200 Public Const PRINTER_STATUS_DOOR_OPEN = &H400000 Public Const PRINTER_STATUS_ERROR = &H2 Public Const PRINTER_STATUS_INITIALIZING = &H8000 Public Const PRINTER_STATUS_IO_ACTIVE = &H100 Public Const PRINTER_STATUS_MANUAL_FEED = &H20 Public Const PRINTER_STATUS_NO_TONER = &H40000 Public Const PRINTER_STATUS_NOT_AVAILABLE = &H1000 Public Const PRINTER_STATUS_OFFLINE = &H80 Public Const PRINTER_STATUS_OUT_OF_MEMORY = &H200000 Public Const PRINTER_STATUS_OUTPUT_BIN_FULL = &H800 Public Const PRINTER_STATUS_PAGE_PUNT = &H80000 Public Const PRINTER_STATUS_PAPER_JAM = &H8 Public Const PRINTER_STATUS_PAPER_OUT = &H10 Public Const PRINTER_STATUS_PAPER_PROBLEM = &H40 Public Const PRINTER_STATUS_PAUSED = &H1 Public Const PRINTER_STATUS_PENDING_DELETION = &H4 Public Const PRINTER_STATUS_PRINTING = &H400 Public Const PRINTER_STATUS_PROCESSING = &H4000 Public Const PRINTER_STATUS_TONER_LOW = &H20000 Public Const PRINTER_STATUS_USER_INTERVENTION = &H100000 Public Const PRINTER_STATUS_WAITING = &H2000 Public Const PRINTER_STATUS_WARMING_UP = &H10000 'Define the job status constants. Public Const JOB_STATUS_PAUSED = &H1 Public Const JOB_STATUS_ERROR = &H2 Public Const JOB_STATUS_DELETING = &H4 Public Const JOB_STATUS_SPOOLING = &H8 Public Const JOB_STATUS_PRINTING = &H10 Public Const JOB_STATUS_OFFLINE = &H20 Public Const JOB_STATUS_PAPEROUT = &H40 Public Const JOB_STATUS_PRINTED = &H80 Public Const JOB_STATUS_DELETED = &H100 Public Const JOB_STATUS_BLOCKED_DEVQ = &H200 Public Const JOB_STATUS_USER_INTERVENTION = &H400 Public Const JOB_STATUS_RESTART = &H800

Public Function GetString(ByVal PtrStr As Long) As String Dim StrBuff As String StrBuff = New String(CChar(&quot;&quot;), 256) 'Determine if a zero address is used. If PtrStr = 0 Then GetString = &quot; &quot; Exit Function End If

'Copy data from PtrStr to the buffer.

Dim PtrInt As IntPtr = New IntPtr(PtrStr) StrBuff = Marshal.PtrToStringAuto(PtrInt)

'Remove any trailing nulls from the string. GetString = StripNulls(StrBuff) End Function

Public Function StripNulls(ByVal OriginalStr As String) As String

'Remove any trailing nulls from the input string. If (InStr(OriginalStr, Chr(0)) > 0) Then OriginalStr = Left(OriginalStr, InStr(OriginalStr, Chr(0)) - 1) End If       'Return the modified string. StripNulls = OriginalStr End Function

Public Function CheckPrinterStatus(ByVal PI2Status As Long) As String Dim tempStr As String If PI2Status = 0 Then  ' Return the &quot;Ready&quot; status. CheckPrinterStatus = &quot;Printer Status = Ready&quot; & vbCrLf Else tempStr = &quot;&quot; 'Determine the printer state. If (PI2Status And PRINTER_STATUS_BUSY) Then tempStr = tempStr & &quot;Busy &quot; End If           If (PI2Status And PRINTER_STATUS_DOOR_OPEN) Then tempStr = tempStr & &quot;Printer Door Open &quot; End If           If (PI2Status And PRINTER_STATUS_ERROR) Then tempStr = tempStr & &quot;Printer Error &quot; End If           If (PI2Status And PRINTER_STATUS_INITIALIZING) Then tempStr = tempStr & &quot;Initializing &quot; End If           If (PI2Status And PRINTER_STATUS_IO_ACTIVE) Then tempStr = tempStr & &quot;I/O Active &quot; End If           If (PI2Status And PRINTER_STATUS_MANUAL_FEED) Then tempStr = tempStr & &quot;Manual Feed &quot; End If           If (PI2Status And PRINTER_STATUS_NO_TONER) Then tempStr = tempStr & &quot;No Toner &quot; End If           If (PI2Status And PRINTER_STATUS_NOT_AVAILABLE) Then tempStr = tempStr & &quot;Not Available &quot; End If           If (PI2Status And PRINTER_STATUS_OFFLINE) Then tempStr = tempStr & &quot;Off Line &quot; End If           If (PI2Status And PRINTER_STATUS_OUT_OF_MEMORY) Then tempStr = tempStr & &quot;Out of Memory &quot; End If           If (PI2Status And PRINTER_STATUS_OUTPUT_BIN_FULL) Then tempStr = tempStr & &quot;Output Bin Full &quot; End If           If (PI2Status And PRINTER_STATUS_PAGE_PUNT) Then tempStr = tempStr & &quot;Page Punt &quot; End If           If (PI2Status And PRINTER_STATUS_PAPER_JAM) Then tempStr = tempStr & &quot;Paper Jam &quot; End If           If (PI2Status And PRINTER_STATUS_PAPER_OUT) Then tempStr = tempStr & &quot;Paper Out &quot; End If           If (PI2Status And PRINTER_STATUS_OUTPUT_BIN_FULL) Then tempStr = tempStr & &quot;Output Bin Full &quot; End If           If (PI2Status And PRINTER_STATUS_PAPER_PROBLEM) Then tempStr = tempStr & &quot;Page Problem &quot; End If           If (PI2Status And PRINTER_STATUS_PAUSED) Then tempStr = tempStr & &quot;Paused &quot; End If           If (PI2Status And PRINTER_STATUS_PENDING_DELETION) Then tempStr = tempStr & &quot;Pending Deletion &quot; End If           If (PI2Status And PRINTER_STATUS_PRINTING) Then tempStr = tempStr & &quot;Printing &quot; End If           If (PI2Status And PRINTER_STATUS_PROCESSING) Then tempStr = tempStr & &quot;Processing &quot; End If           If (PI2Status And PRINTER_STATUS_TONER_LOW) Then tempStr = tempStr & &quot;Toner Low &quot; End If           If (PI2Status And PRINTER_STATUS_USER_INTERVENTION) Then tempStr = tempStr & &quot;User Intervention &quot; End If           If (PI2Status And PRINTER_STATUS_WAITING) Then tempStr = tempStr & &quot;Waiting &quot; End If           If (PI2Status And PRINTER_STATUS_WARMING_UP) Then tempStr = tempStr & &quot;Warming Up &quot; End If           If Len(tempStr) = 0 Then tempStr = &quot;Unknown Status of &quot; & PI2Status End If           'Return the status. CheckPrinterStatus = &quot;Printer Status = &quot; & tempStr & vbCrLf End If   End Function End Module </li> In Solution Explorer, right-click the Form1.vb file, and then click View Code.</li>  In the Form1.vb file, replace the existing code with the following sample code. Imports System.Diagnostics.Debug Imports System.Drawing.Printing Imports System.Runtime.InteropServices

Public Class Form1 Inherits System.Windows.Forms.Form

Public Sub New MyBase.New 'This call is required by the Windows Form Designer. InitializeComponent 'Add any initialization after the InitializeComponent call End Sub
 * 1) Region &quot; Windows Form Designer generated code &quot;

'Form overrides dispose to clean up the component list. Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean) If disposing Then If Not (components Is Nothing) Then components.Dispose End If       End If        MyBase.Dispose(disposing) End Sub

'Required by the Windows Form Designer Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer 'It can be modified using the Windows Form Designer. 'Do not modify it using the code editor. Friend WithEvents TextBox1 As System.Windows.Forms.TextBox Friend WithEvents TextBox2 As System.Windows.Forms.TextBox Friend WithEvents Command1 As System.Windows.Forms.Button Friend WithEvents Command2 As System.Windows.Forms.Button Friend WithEvents Command3 As System.Windows.Forms.Button Friend WithEvents Timer1 As System.Windows.Forms.Timer Friend WithEvents TextBox3 As System.Windows.Forms.TextBox <System.Diagnostics.DebuggerStepThrough> Private Sub InitializeComponent Me.components = New System.ComponentModel.Container Me.Command1 = New System.Windows.Forms.Button Me.Command2 = New System.Windows.Forms.Button Me.Command3 = New System.Windows.Forms.Button Me.TextBox1 = New System.Windows.Forms.TextBox Me.TextBox2 = New System.Windows.Forms.TextBox Me.Timer1 = New System.Windows.Forms.Timer(Me.components) Me.TextBox3 = New System.Windows.Forms.TextBox Me.SuspendLayout '       'Command1 '       Me.Command1.Location = New System.Drawing.Point(352, 24) Me.Command1.Name = &quot;Command1&quot; Me.Command1.Size = New System.Drawing.Size(136, 23) Me.Command1.TabIndex = 0 Me.Command1.Text = &quot;Button1&quot; '       'Command2 '       Me.Command2.Location = New System.Drawing.Point(360, 112) Me.Command2.Name = &quot;Command2&quot; Me.Command2.Size = New System.Drawing.Size(128, 23) Me.Command2.TabIndex = 1 Me.Command2.Text = &quot;Button2&quot; '       'Command3 '       Me.Command3.Location = New System.Drawing.Point(360, 224) Me.Command3.Name = &quot;Command3&quot; Me.Command3.Size = New System.Drawing.Size(128, 23) Me.Command3.TabIndex = 2 Me.Command3.Text = &quot;Button3&quot; '       'TextBox1 '       Me.TextBox1.Location = New System.Drawing.Point(8, 24) Me.TextBox1.Multiline = True Me.TextBox1.Name = &quot;TextBox1&quot; Me.TextBox1.Size = New System.Drawing.Size(320, 80) Me.TextBox1.TabIndex = 3 Me.TextBox1.Text = &quot;TextBox1&quot; '       'TextBox2 '       Me.TextBox2.Location = New System.Drawing.Point(8, 120) Me.TextBox2.Multiline = True Me.TextBox2.Name = &quot;TextBox2&quot; Me.TextBox2.Size = New System.Drawing.Size(320, 80) Me.TextBox2.TabIndex = 4 Me.TextBox2.Text = &quot;TextBox2&quot; '       'Timer1 '       Me.Timer1.Enabled = True '       'TextBox3 '       Me.TextBox3.Location = New System.Drawing.Point(8, 216) Me.TextBox3.Multiline = True Me.TextBox3.Name = &quot;TextBox3&quot; Me.TextBox3.ScrollBars = System.Windows.Forms.ScrollBars.Vertical Me.TextBox3.Size = New System.Drawing.Size(320, 80) Me.TextBox3.TabIndex = 5 Me.TextBox3.Text = &quot;TextBox3&quot; '       'Form1 '       Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13) Me.ClientSize = New System.Drawing.Size(504, 317) Me.Controls.Add(Me.TextBox3) Me.Controls.Add(Me.TextBox2) Me.Controls.Add(Me.TextBox1) Me.Controls.Add(Me.Command3) Me.Controls.Add(Me.Command2) Me.Controls.Add(Me.Command1) Me.Name = &quot;Form1&quot; Me.Text = &quot;Form1&quot; Me.ResumeLayout(False) End Sub
 * 1) End Region

Public Shared Sub main Dim PrntInfo As New Form1 PrntInfo.ShowDialog End Sub

Private Sub Command1_Click(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles Command1.Click 'Enable the timer to start printer status checks. Timer1.Enabled = True Timer1.Start

'Enable and disable the start and stop buttons. Command1.Enabled = False Command2.Enabled = True Command3.Enabled = True End Sub

Private Sub Command2_Click(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles Command2.Click 'Disable the timer to stop additional printer checks. Timer1.Enabled = False

'Enable and disable the start and stop buttons. Command1.Enabled = True Command2.Enabled = False Command3.Enabled = True API = Nothing End Sub

Private Sub Command3_Click(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles Command3.Click 'Clear the text boxes to display the printer status. TextBox1.Text = &quot;&quot; TextBox2.Text = &quot;&quot; TextBox3.Text = &quot;&quot; End Sub

Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) _ Handles MyBase.Load 'Initialize captions for the buttons. Command1.Text = &quot;Start&quot; Command2.Text = &quot;Stop&quot; Command3.Text = &quot;Clear&quot;

'Clear the text boxes to display the printer status. TextBox1.Text = &quot;&quot; TextBox2.Text = &quot;&quot; TextBox3.Text = &quot;&quot;

Command1.Enabled = True 'Disable the stop and clear buttons. Command2.Enabled = False Command3.Enabled = False

'Set the timer interval to 500 milliseconds to examine the printer status. Timer1.Enabled = False Timer1.Interval = 500 End Sub

Private Sub Timer1_Tick(ByVal sender As System.Object, _       ByVal e As System.EventArgs) Handles Timer1.Tick Dim PrinterStatus As String Dim JobStatus As String Dim ErrorInfo As String

'Clear the text boxes to display the status. TextBox1.Text = &quot;&quot; TextBox2.Text = &quot;&quot; TextBox3.Text = &quot;&quot;

'Call the CheckPrinter function. TextBox1.Text = CheckPrinter(PrinterStatus, JobStatus) TextBox2.Text = PrinterStatus TextBox3.Text = JobStatus End Sub

Public Function CheckPrinter(ByRef PrinterStr As String, _       ByRef JobStr As String) As String Dim hPrinter As IntPtr Dim ByteBuf As Long Dim BytesNeeded As Int32 Dim PI2 As New PRINTER_INFO_2 Dim intCount As Long Dim JI2(intCount) As JOB_INFO_2 Dim PrinterInfo As Byte Dim JobInfo As Byte Dim result As Long Dim LastError As Long Dim PrinterName As String Dim tempStr As String Dim NumJI2 As Int32 Dim pDefaults As PRINTER_DEFAULTS

'Set a default return value if no errors occur. CheckPrinter = &quot;Printer info retrieved!&quot;

Dim PD As New PrintDocument PrinterName = PD.PrinterSettings.PrinterName

'Set the access security setting that you want. pDefaults.DesiredAccess = PRINTER_ACCESS_USE

'Call the API to obtain a handle to the printer. 'If an error occurs, display the error. result = API.OpenPrinter(PrinterName, hPrinter, pDefaults) If result = 0 Then

CheckPrinter = &quot;Cannot open printer &quot; & PrinterName & _ &quot;, Error: &quot; & Marshal.GetLastWin32Error Exit Function End If

'Initialize the BytesNeeded variable. BytesNeeded = 0

'Clear the error object. Err.Clear

'Determine the buffer size that is required to obtain the printer information. result = API.GetPrinter(hPrinter, 2, 0&, 0, BytesNeeded) 'Display the error message that you receive when you call the GetPrinter function, 'and then close the printer handle. If Marshal.GetLastWin32Error <> ERROR_INSUFFICIENT_BUFFER Then CheckPrinter = &quot; > GetPrinter Failed on initial call! <&quot; API.ClosePrinter(hPrinter) Exit Function End If       ReDim PrinterInfo(BytesNeeded) ByteBuf = BytesNeeded

'Call the GetPrinter function to obtain the status. result = API.GetPrinter(hPrinter, 2, PrinterInfo(0), ByteBuf, _         BytesNeeded)

'Check for any errors. If result = 0 Then 'Get the error. LastError = Marshal.GetLastWin32Error

'Display the error message, and then close the printer handle. CheckPrinter = &quot;Could not get Printer Status! Error = &quot; _ & LastError API.ClosePrinter(hPrinter) Exit Function End If

'Copy the contents of the printer status byte array into a       'PRINTER_INFO_2 structure. PI2 = CType(DatatoDeserial(PrinterInfo, GetType(PRINTER_INFO_2), 1), PRINTER_INFO_2) PrinterStr = CheckPrinterStatus(PI2.Status)

'Add the printer name, the driver, and the port to the text box. PrinterStr = PrinterStr & &quot;Printer Name = &quot; & _ GetString(PI2.pPrinterName) & vbCrLf PrinterStr = PrinterStr & &quot;Printer Driver Name = &quot; & _ GetString(PI2.pDriverName) & vbCrLf PrinterStr = PrinterStr & &quot;Printer Port Name = &quot; & _ GetString(PI2.pPortName) & vbCrLf

'Call the API to obtain the buffer size that is required. result = API.EnumJobs(hPrinter, 0, &HFFFFFFFF, 2, JobInfo, 0, BytesNeeded, NumJI2) If result = 0 Then 'Display the error, and then close the printer handle. LastError = Marshal.GetLastWin32Error CheckPrinter = &quot; > EnumJobs Failed on initial call! < Error = &quot; _ & LastError API.ClosePrinter(hPrinter) Exit Function End If

'If no current jobs exist, display the message. If BytesNeeded = 0 Then JobStr = &quot;No Print Jobs!&quot; Else 'Resize the byte array to hold information about the print jobs. ReDim JobInfo(BytesNeeded - 1)

'Call the API to obtain the print job information. result = API.EnumJobs(hPrinter, 0, &HFFFFFFFF, 2, JobInfo, _               BytesNeeded, BytesNeeded, NumJI2)

'Check for errors. If result = 0 Then 'Display the error, and then close the printer handle. LastError = Marshal.GetLastWin32Error CheckPrinter = &quot; > EnumJobs Failed on second call! < Error = &quot; _ & LastError API.ClosePrinter(hPrinter) Exit Function End If           ReDim JI2(NumJI2)

'Copy the contents of print job info byte array into a           'JOB_INFO_2 structure. Try For intCount = 0 To NumJI2 - 1 ' Loop through jobs and obtain the job information. Dim test As Object JI2(intCount) = CType(DatatoDeserial(JobInfo, _ GetType(JOB_INFO_2), intCount + 1), JOB_INFO_2)

JobStr = JobStr & &quot;Job ID = &quot; & JI2(intCount).PrinterJobId & _ vbCrLf & &quot;Total Pages = &quot; & JI2(intCount).TotalPages & vbCrLf

tempStr = &quot;&quot; 'Check for a ready state. If JI2(intCount).pStatus = 0& Then  ' If pStatus is Null, check Status. If JI2(intCount).pStatus = 0 Then tempStr = tempStr & &quot;Ready! &quot; & vbCrLf Else 'Check for the various print job states. If (JI2(intCount).pStatus And JOB_STATUS_SPOOLING) Then tempStr = tempStr & &quot;Spooling &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_OFFLINE) Then tempStr = tempStr & &quot;Off line &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_PAUSED) Then tempStr = tempStr & &quot;Paused &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_ERROR) Then tempStr = tempStr & &quot;Error &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_PAPEROUT) Then tempStr = tempStr & &quot;Paper Out &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_PRINTING) Then tempStr = tempStr & &quot;Printing &quot; End If

If (JI2(intCount).pStatus And JOB_STATUS_USER_INTERVENTION) Then tempStr = tempStr & &quot;User Intervention Needed &quot; End If

If Len(tempStr) = 0 Then tempStr = &quot;Unknown Status of &quot; & JI2(intCount).PrinterStatus End If                       End If                    Else

tempStr = Pointer_to_String(JI2(intCount).pStatus) End If

'Report the job status. JobStr = JobStr & tempStr & vbCrLf Next intCount Catch ex As Exception MessageBox.Show(ex.Message) End Try End If       'Close the printer handle. API.ClosePrinter(hPrinter) End Function End Class </li> On the Build menu, click Build Solution.</li> Click Start, and then click Printers and Faxes.

Note On a computer that is running Microsoft Windows 2000, click Start, point to Settings, and then click Printers.</li> In the Printers and Faxes window, double-click the icon for the printer whose queue you want to view.

Note In the Printers window on a computer that is running Windows 2000, double-click the icon for the printer whose queue you want to view.</li> On the Printer menu in the PrinterName dialog box, click Pause Printing.

Note You may not be able to pause the print queue on a network printer.</li> On the Debug menu in Visual Studio .NET, click Start to run the application.</li> In the Form1 form, click Start to obtain the printer information and the list of jobs in the queue.</li></ol>

back to the top

Troubleshooting
Only a specific device driver can obtain accurate printer status information. This sample code obtains the same status that the Windows spooler reports.

The exact status that is reported may vary for different printers and for different drivers.

back to the top

<div class="references_section">