Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Verify a printer is operational without test page...

Status
Not open for further replies.

OrthoDocSoft

Programmer
Joined
May 7, 2004
Messages
291
Location
US
Folks,

My app writes to two different printers. Is there a way to switch between them and "test" whether the software can "see" (and, thus, write to) the printers without printing a test page?

After this algo, I would like the software to say "Both printers are ready," or "not" if not.

Thanks,

Ortho


[lookaround] "you cain't fix 'stupid'...
 
NOTE: The system only checks the status when the system has a job to spool. Otherwise, the queue is considered "ready" because the queue can accept jobs, even if the hardware is in an error state. For example, if the last job that was printed used the last piece of paper, the operating system does not know this until the system tries to print again."

You may wish to test after the print job was sent too. I use this with some of my printers. Others I use a manufacturer specific dll to retrieve a more accurate status. This example is probably suficient in most cases and is useful for any spooler printer regardless of manufacturer.


Tom
 
Tom,

Thanks, I'll check that out, but it will take me some time. That looks somewhat complicated.

Ortho

[lookaround] "you cain't fix 'stupid'...
 
Well I can give you my simplified version of that.


Code:
Public Function pCheckPrinter(PrinterStr As String, JobStr As String, MyStatusStr As String, StatusType As String, MyPrinterName As String, MyPrinterIP As String) As String
   
   On Error GoTo pCheckPrinter_Error

  If StatusType = "Windows Spooler" Then
    pCheckPrinter = pCheckPrinterWindows(PrinterStr, JobStr, MyStatusStr, MyPrinterName)
  ElseIf StatusType = "Print Server" Then
    pCheckPrinter = pCheckPrinterWindows(PrinterStr, JobStr, MyStatusStr, "[URL unfurl="true"]http://"[/URL] & MyPrinterIP)
  Else ' NetworkPrinter
    pCheckPrinter = pCheckPrinterStarIO(PrinterStr, JobStr, MyStatusStr, "tcp:" & MyPrinterIP)
  End If

   On Error GoTo 0
   Exit Function

pCheckPrinter_Error:

  MsgBox "Error " & Err.number & " (" & Err.Description & ") , Line - " & Erl & ", in procedure pCheckPrinter of Module PrinterStatusMod"

   
End Function

Code:
Public Function pCheckPrinterWindows(PrinterStr As String, JobStr As String, MyStatusStr As String, MyPrinterName As String) As String
   
   Dim hPrinter As Long
   Dim ByteBuf As Long
   Dim BytesNeeded As Long
   Dim PI2 As PRINTER_INFO_2
   Dim JI2 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 Long
   Dim pDefaults As PRINTER_DEFAULTS
   Dim i As Integer
   
   
   
   
   On Error GoTo pCheckPrinterWindows_Error

   'Set a default return value if no errors occur.
   pCheckPrinterWindows = "Printer info retrieved"
   
   'NOTE: You can pick a printer from the Printers Collection
   'or use the EnumPrinters() API to select a printer name.
   
   'Use the default printer of Printers collection.
   'This is typically, but not always, the system default printer.
   'PrinterName = Printer.DeviceName
   'PrinterName = "[URL unfurl="true"]http://192.168.0.100"[/URL] ' WORKS
   'PrinterName = "Star TSP100 Cutter (TSP143) on QUICK1"
   'PrinterName = "\\quick1\Star TSP100 Cutter (TSP143)"
   PrinterName = MyPrinterName '"\\quick1\Local"
   'PrinterName = enumprinters()
   'PrinterName = "Star TSP100 Cutter (TSP143)"
   'Set desired access security setting.
   pDefaults.DesiredAccess = PRINTER_ACCESS_USE
   
   'Call API to get a handle to the printer.
   result = OpenPrinter(PrinterName, hPrinter, pDefaults)
   If result = 0 Then
      'If an error occurred, display an error and exit sub.
      pCheckPrinterWindows = "Cannot open printer " & PrinterName & _
         ", Error: " & Err.LastDllError
      Exit Function
   End If

   'Init BytesNeeded
   BytesNeeded = 0

   'Clear the error object of any errors.
   Err.Clear

   'Determine the buffer size that is needed to get printer info.
   result = GetPrinter(hPrinter, 2, 0&, 0&, BytesNeeded)
   
   'Check for error calling GetPrinter.
   If Err.LastDllError <> ERROR_INSUFFICIENT_BUFFER Then
      'Display an error message, close printer, and exit sub.
      pCheckPrinterWindows = " > GetPrinter Failed on initial call! <"
      ClosePrinter hPrinter
      Exit Function
   End If
   
   'Note that in Charles Petzold's book "Programming Windows 95," he
   'states that because of a problem with GetPrinter on Windows 95 only, you
   'must allocate a buffer as much as three times larger than the value
   'returned by the initial call to GetPrinter. This is not done here.
   ReDim PrinterInfo(1 To BytesNeeded)
   
   ByteBuf = BytesNeeded
   
   'Call GetPrinter to get the status.
   result = GetPrinter(hPrinter, 2, PrinterInfo(1), ByteBuf, _
     BytesNeeded)
   
   'Check for errors.
   If result = 0 Then
      'Determine the error that occurred.
      LastError = Err.LastDllError()
      
      'Display error message, close printer, and exit sub.
      pCheckPrinterWindows = "Couldn't get Printer Status!  Error = " _
         & LastError
      ClosePrinter hPrinter
      Exit Function
   End If

   'Copy contents of printer status byte array into a
   'PRINTER_INFO_2 structure to separate the individual elements.
   CopyMemory PI2, PrinterInfo(1), Len(PI2)
   
   'Check if printer is in ready state.
   
   PrinterStr = CheckPrinterStatus(PI2.Status, MyStatusStr)
   
   'Add printer name, driver, and port to list.
   PrinterStr = PrinterStr & "Printer Name = " & _
     GetString(PI2.pPrinterName) & vbCrLf
   PrinterStr = PrinterStr & "Printer Driver Name = " & _
     GetString(PI2.pDriverName) & vbCrLf
   PrinterStr = PrinterStr & "Printer Port Name = " & _
     GetString(PI2.pPortName) & vbCrLf
   
   'Call API to get size of buffer that is needed.
   result = EnumJobs(hPrinter, 0&, &HFFFFFFFF, 2, ByVal 0&, 0&, _
      BytesNeeded, NumJI2)
   
   'Check if there are no current jobs, and then display appropriate message.
   If BytesNeeded = 0 Then
      JobStr = "No Print Jobs!"
   Else
      'Redim byte array to hold info about print job.
      ReDim JobInfo(0 To BytesNeeded)
      
      'Call API to get print job info.
      result = EnumJobs(hPrinter, 0&, &HFFFFFFFF, 2, JobInfo(0), _
        BytesNeeded, ByteBuf, NumJI2)
      
      'Check for errors.
      If result = 0 Then
         'Get and display error, close printer, and exit sub.
         LastError = Err.LastDllError
         pCheckPrinterWindows = " > EnumJobs Failed on second call! <  Error = " _
            & LastError
         ClosePrinter hPrinter
         Exit Function
      End If
      
      'Copy contents of print job info byte array into a
      'JOB_INFO_2 structure to separate the individual elements.
      For i = 0 To NumJI2 - 1   ' Loop through jobs and walk the buffer
          CopyMemory JI2, JobInfo(i * Len(JI2)), Len(JI2)
             
          ' List info available on Jobs.
          Debug.Print "Job ID" & vbTab & JI2.JobId
          Debug.Print "Name Of Printer" & vbTab & _
            GetString(JI2.pPrinterName)
          Debug.Print "Name Of Machine That Created Job" & vbTab & _
            GetString(JI2.pMachineName)
          Debug.Print "Print Job Owner's Name" & vbTab & _
            GetString(JI2.pUserName)
          Debug.Print "Name Of Document" & vbTab & GetString(JI2.pDocument)
          Debug.Print "Name Of User To Notify" & vbTab & _
            GetString(JI2.pNotifyName)
          Debug.Print "Type Of Data" & vbTab & GetString(JI2.pDatatype)
          Debug.Print "Print Processor" & vbTab & _
            GetString(JI2.pPrintProcessor)
          Debug.Print "Print Processor Parameters" & vbTab & _
            GetString(JI2.pParameters)
          Debug.Print "Print Driver Name" & vbTab & _
            GetString(JI2.pDriverName)
          Debug.Print "Print Job 'P' Status" & vbTab & _
            GetString(JI2.pStatus)
          Debug.Print "Print Job Status" & vbTab & JI2.Status
          Debug.Print "Print Job Priority" & vbTab & JI2.Priority
          Debug.Print "Position in Queue" & vbTab & JI2.Position
          Debug.Print "Earliest Time Job Can Be Printed" & vbTab & _
            JI2.StartTime
          Debug.Print "Latest Time Job Will Be Printed" & vbTab & _
            JI2.UntilTime
          Debug.Print "Total Pages For Entire Job" & vbTab & JI2.TotalPages
          Debug.Print "Size of Job In Bytes" & vbTab & JI2.size
          'Because of a bug in Windows NT 3.51, the time member is not set correctly.
          'Therefore, do not use the time member on Windows NT 3.51.
          Debug.Print "Elapsed Print Time" & vbTab & JI2.time
          Debug.Print "Pages Printed So Far" & vbTab & JI2.PagesPrinted
             
          'Display basic job status info.
          JobStr = JobStr & "Job ID = " & JI2.JobId & _
             vbCrLf & "Total Pages = " & JI2.TotalPages & vbCrLf
          
          tempStr = ""   'Clear
          'Check for a ready state.
          If JI2.pStatus = 0& Then   ' If pStatus is Null, check Status.
            If JI2.Status = 0 Then
               tempStr = tempStr & "Ready!  " & vbCrLf
            Else  'Check for the various print job states.
               If (JI2.Status And JOB_STATUS_SPOOLING) Then
                  tempStr = tempStr & "Spooling  "
               End If
               
               If (JI2.Status And JOB_STATUS_OFFLINE) Then
                  tempStr = tempStr & "Off line  "
               End If
               
               If (JI2.Status And JOB_STATUS_PAUSED) Then
                  tempStr = tempStr & "Paused  "
               End If
               
               If (JI2.Status And JOB_STATUS_ERROR) Then
                  tempStr = tempStr & "Error  "
               End If
               
               If (JI2.Status And JOB_STATUS_PAPEROUT) Then
                  tempStr = tempStr & "Paper Out  "
               End If
               
               If (JI2.Status And JOB_STATUS_PRINTING) Then
                  tempStr = tempStr & "Printing  "
               End If
               
               If (JI2.Status And JOB_STATUS_USER_INTERVENTION) Then
                  tempStr = tempStr & "User Intervention Needed  "
               End If
               
               If Len(tempStr) = 0 Then
                  tempStr = "Unknown Status of " & JI2.Status
               End If
            End If
        Else
            ' Dereference pStatus.
            tempStr = PtrCtoVbString(JI2.pStatus)
        End If
          
          'Report the Job status.
          JobStr = JobStr & tempStr & vbCrLf
          Debug.Print JobStr & tempStr
      Next i
   End If
   
   'Close the printer handle.
   ClosePrinter hPrinter



   On Error GoTo 0
   Exit Function

pCheckPrinterWindows_Error:

  MsgBox "Error " & Err.number & " (" & Err.Description & ") , Line - " & Erl & ", in procedure pCheckPrinterWindows of Module PrinterStatusMod"

End Function

Maybe not so simple but its the function in the first part that returns the result. Copy and paste most. Sorry I didn't edit it for simplicity but call as a function and return the result. There is a lot of extra stuff here but use the first part where it says "StatusType = "Windows Spooler"" get rid of the rest and go from there. I can break it down better later but its getting late here right now and I'm going to bed.





Tom
 
I accidently hit Submit instead of preview so there is a lot of my specific code included there. If needed I can break it down for you tommorrow. Also there are comments from the original author that I got this from based off the MS article.

Tom
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top