Benutzer mit den meisten Antworten
Druckerstatus

Frage
-
Hallo zusammen
Ich versuche vor dem Drucken den Status festzustellen, ob er Betriebsbereit ist (eigeschaltet, Papier vorhanden, ...).
Bei Abfrage GetPrintQueues() und Auswerten des "QueueStatus" kommt bei zwei HP Lasern die Info offline, bei zwei Tintenstrhldruckern kommt die Info nicht.
PrintDocument.PrinterSettings.IsValid bringt immer True.
Auch bei Drucker die nicht angeschlossen sind.ManagementObjectSearcher -> ManagementObjectCollection -> ManagementObject auswerten von "PrinterState" und "PrinterStatus" komme ich auf keinen grünen Zweig.
Kann mir jemand sagen, wie ich die Information über den Druckerstatus bekommen kann?
Ich muss kapitulieren.Danke und Gruss
Peter
Antworten
-
Hallo Peter,
ich komme an die Status-Infos über API-Calls zu WINSPOOL.DRV:
OpenPrinter um das Handle zu kriegen.
Dann GetPrinter um an die Infos (in einer Binär-Struktur) zu kommen.
Darin steckt auch ein DWORD mit den ganzen Status-Bits (ready, paused, error, offline, paperout etc.)
Zum Schluss natürlich dann ClosePrinter.
Gruß,
WiWo
- Als Antwort markiert peter haus Freitag, 11. Juli 2014 11:50
Alle Antworten
-
Hallo Peter,
ich komme an die Status-Infos über API-Calls zu WINSPOOL.DRV:
OpenPrinter um das Handle zu kriegen.
Dann GetPrinter um an die Infos (in einer Binär-Struktur) zu kommen.
Darin steckt auch ein DWORD mit den ganzen Status-Bits (ready, paused, error, offline, paperout etc.)
Zum Schluss natürlich dann ClosePrinter.
Gruß,
WiWo
- Als Antwort markiert peter haus Freitag, 11. Juli 2014 11:50
-
Hallo Alexander,
den Code setze ich mal rein.
Allerdings ist es mein Testcode, mit dem ich nicht wirklich weiter gekommen bin, zum Teil mit fest vorgegebenen Druckernamen. Da ich nicht wirklich sehen konnte, das die gewünschte Information kam, habe ich aufgegeben.
Wenn du dazu eine Anmerkung hast würde es mich interessieren.
Gruss Peter
Imports System.Printing
'!!!
'Unvollständige Klasse zum ermitteln des Druckerstatus
'!!!
Public Class clsPrintQueue
' Create a PrintServer
' "theServer" must be a print server to which the user has full print access.
Public Sub PrintServer()
Dim myPrintServer As New PrintServer("\\KH-HP")' List the print server's queues
Dim myPrintQueues As PrintQueueCollection = myPrintServer.GetPrintQueues()
Dim printQueueNames As String = "My Print Queues:" & vbLf & vbLf
For Each pq As PrintQueue In myPrintQueues
If pq.Name.ToUpperInvariant().Contains("ONENOTE") OrElse pq.Name.ToUpperInvariant().Contains("REDIRECTED") Then
'The OneNote printer driver causes crashes in 64bit OSes so for now just don't include it.
' Also redirected printer drivers cause crashes for some printers.
Continue For
End IfprintQueueNames &= vbTab & pq.Name & vbLf
Next pq
Debug.WriteLine(printQueueNames)
Debug.WriteLine(vbLf & "Press Return to continue.")End Sub
Public Sub PrintQueueInfo()
Dim sH As String
Dim ps As New PrintServer()
Dim pq As PrintQueueDim useAttributesResponse As String = "Y"
Try
Dim s As String = "Canon Inkjet MP600 Printer"
s = "EPSON SX430 Series"pq = ps.GetPrintQueue(s)
Dim statusReport As String = ""
SpotTroubleUsingQueueAttributes(statusReport, pq)
Dim myPS As New PrintServer("\\KH-HP", PrintSystemDesiredAccess.AdministrateServer)
Dim myPrintQueues As PrintQueueCollection = myPS.GetPrintQueues()
For Each pq In myPrintQueues
pq.Refresh()
statusReport = statusReport & vbLf & vbTab & pq.Name & ":"
SpotTroubleUsingQueueAttributes(statusReport, pq)
Next pq ' end for each print queue
'-----------------
s = "NPIFC75A2 (HP Color LaserJet CP2025dn)"
pq = ps.GetPrintQueue(s)
Dim jobList As String = ""
'For Each pq In myPrintQueues
pq.Refresh()
Dim jobs As PrintJobInfoCollection = pq.GetPrintJobInfoCollection()
For Each job As PrintSystemJobInfo In jobs
' Since the user may not be able to articulate which job is problematic,
' present information about each job the user has submitted.
If job.Submitter = "kh" Then ' "KH"
Dim atLeastOne = True
jobList = jobList & vbLf & "Server:" & "KH-HP"
jobList = jobList & vbLf & vbTab & "Queue:" & pq.Name
jobList = jobList & vbLf & vbTab & "Location:" & pq.Location
jobList = jobList & vbLf & vbTab & vbTab & "Job: " & job.JobName & " ID: " & job.JobIdentifier' Create objects to represent the server, queue, and print job.
Dim hostingServer0 As New PrintServer("\\" & Environment.MachineName, PrintSystemDesiredAccess.AdministrateServer)
Dim hostingQueue0 As New PrintQueue(hostingServer0, pq.Name, PrintSystemDesiredAccess.AdministratePrinter)
Dim theJob0 As PrintSystemJobInfo = hostingQueue0.GetJob(job.JobIdentifier)If useAttributesResponse = "Y" Then
SpotTroubleUsingJobAttributes2(theJob0)
' TroubleSpotter class is defined in the complete example.
Else
SpotTroubleUsingProperties2(theJob0)
End If'ReportQueueAndJobAvailability(theJob )
ReportQueueAndJobAvailability(theJob0, pq)
End If
Next job ' end for each print job'Next pq
'############################
' When the problematic print job has been identified, enter information about it.
Console.Write(vbLf & "Enter the print server hosting the job (including leading slashes \\): " & vbLf & "(press Return for the current computer \\{0}): ", Environment.MachineName)
Dim pServer As String = Console.ReadLine()
If pServer = "" Then
pServer = "\\" & Environment.MachineName
End If
Console.Write(vbLf & "Enter the print queue hosting the job: ")
Dim pQueue As String = "Canon Inkjet MP600 Printer" ' NPIFC75A2 (HP Color LaserJet CP2025dn)
Console.Write(vbLf & "Enter the job ID: ")
Dim jobID As Int16 = 6 'Z. B. ID=6' Create objects to represent the server, queue, and print job.
Dim hostingServer As New PrintServer(pServer, PrintSystemDesiredAccess.AdministrateServer)
Dim hostingQueue As New PrintQueue(hostingServer, pQueue, PrintSystemDesiredAccess.AdministratePrinter)
Dim theJob As PrintSystemJobInfo = hostingQueue.GetJob(jobID)If useAttributesResponse = "Y" Then
SpotTroubleUsingJobAttributes2(theJob)
' TroubleSpotter class is defined in the complete example.
Else
SpotTroubleUsingProperties2(theJob)
End If'ReportQueueAndJobAvailability(theJob )
ReportQueueAndJobAvailability(theJob, hostingQueue)
'#################
Debug.WriteLine(statusReport, hostingQueue)
Catch ex As Exception
Beep()
End Try
End Sub' Check for possible trouble states of a printer using the flags of the QueueStatus property
Friend Shared Sub SpotTroubleUsingQueueAttributes(ByRef statusReport As String, ByVal pq As PrintQueue)
If (pq.QueueStatus And PrintQueueStatus.PaperProblem) = PrintQueueStatus.PaperProblem Then
statusReport = statusReport & "Has a paper problem. "
End If
If (pq.QueueStatus And PrintQueueStatus.NoToner) = PrintQueueStatus.NoToner Then
statusReport = statusReport & "Is out of toner. "
End If
If (pq.QueueStatus And PrintQueueStatus.DoorOpen) = PrintQueueStatus.DoorOpen Then
statusReport = statusReport & "Has an open door. "
End If
If (pq.QueueStatus And PrintQueueStatus.Error) = PrintQueueStatus.Error Then
statusReport = statusReport & "Is in an error state. "
End If
If (pq.QueueStatus And PrintQueueStatus.NotAvailable) = PrintQueueStatus.NotAvailable Then
statusReport = statusReport & "Is not available. "
End If
If (pq.QueueStatus And PrintQueueStatus.Offline) = PrintQueueStatus.Offline Then
statusReport = statusReport & "Is off line. "
End If
If (pq.QueueStatus And PrintQueueStatus.OutOfMemory) = PrintQueueStatus.OutOfMemory Then
statusReport = statusReport & "Is out of memory. "
End If
If (pq.QueueStatus And PrintQueueStatus.PaperOut) = PrintQueueStatus.PaperOut Then
statusReport = statusReport & "Is out of paper. "
End If
If (pq.QueueStatus And PrintQueueStatus.OutputBinFull) = PrintQueueStatus.OutputBinFull Then
statusReport = statusReport & "Has a full output bin. "
End If
If (pq.QueueStatus And PrintQueueStatus.PaperJam) = PrintQueueStatus.PaperJam Then
statusReport = statusReport & "Has a paper jam. "
End If
If (pq.QueueStatus And PrintQueueStatus.Paused) = PrintQueueStatus.Paused Then
statusReport = statusReport & "Is paused. "
End If
If (pq.QueueStatus And PrintQueueStatus.TonerLow) = PrintQueueStatus.TonerLow Then
statusReport = statusReport & "Is low on toner. "
End If
If (pq.QueueStatus And PrintQueueStatus.UserIntervention) = PrintQueueStatus.UserIntervention Then
statusReport = statusReport & "Needs user intervention. "
End If' Check if queue is even available at this time of day
' The method below is defined in the complete example.
ReportAvailabilityAtThisTime(statusReport, pq)
End Sub
Private Shared Sub ReportAvailabilityAtThisTime(ByRef statusReport As String, ByVal pq As PrintQueue)
If pq.StartTimeOfDay <> pq.UntilTimeOfDay Then ' If the printer is not available 24 hours a day
Dim utcNow As Date = Date.UtcNow
Dim utcNowAsMinutesAfterMidnight As Int32 = (utcNow.TimeOfDay.Hours * 60) + utcNow.TimeOfDay.Minutes' If now is not within the range of available times . . .
If Not ((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight) AndAlso (utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)) Then
statusReport = statusReport & " Is not available at this time of day. "
End If
End If
End Sub' Check for possible trouble states of a print job using the flags of the JobStatus property
Friend Shared Function SpotTroubleUsingJobAttributes2(ByVal theJob As PrintSystemJobInfo) As String
Dim returnString As String = ""If (theJob.JobStatus And PrintJobStatus.Blocked) = PrintJobStatus.Blocked Then
returnString = "The job is blocked."
End If
If ((theJob.JobStatus And PrintJobStatus.Completed) = PrintJobStatus.Completed) OrElse ((theJob.JobStatus And PrintJobStatus.Printed) = PrintJobStatus.Printed) Then
returnString = "The job has finished. Have user recheck all output bins and be sure the correct printer is being checked."
End If
If ((theJob.JobStatus And PrintJobStatus.Deleted) = PrintJobStatus.Deleted) OrElse ((theJob.JobStatus And PrintJobStatus.Deleting) = PrintJobStatus.Deleting) Then
returnString = "The user or someone with administration rights to the queue has deleted the job. It must be resubmitted."
End If
If (theJob.JobStatus And PrintJobStatus.Error) = PrintJobStatus.Error Then
returnString = "The job has errored."
End If
If (theJob.JobStatus And PrintJobStatus.Offline) = PrintJobStatus.Offline Then
returnString = "The printer is offline. Have user put it online with printer front panel."
End If
If (theJob.JobStatus And PrintJobStatus.PaperOut) = PrintJobStatus.PaperOut Then
returnString = "The printer is out of paper of the size required by the job. Have user add paper."
End IfIf ((theJob.JobStatus And PrintJobStatus.Paused) = PrintJobStatus.Paused) OrElse ((theJob.HostingPrintQueue.QueueStatus And PrintQueueStatus.Paused) = PrintQueueStatus.Paused) Then
HandlePausedJob(theJob)
'HandlePausedJob is defined in the complete example.
End IfIf (theJob.JobStatus And PrintJobStatus.Printing) = PrintJobStatus.Printing Then
returnString = "The job is printing now."
End If
If (theJob.JobStatus And PrintJobStatus.Spooling) = PrintJobStatus.Spooling Then
returnString = "The job is spooling now."
End If
If (theJob.JobStatus And PrintJobStatus.UserIntervention) = PrintJobStatus.UserIntervention Then
returnString = "The printer needs human intervention."
End If
Return returnString
End Function 'end SpotTroubleUsingJobAttributes' Check for possible trouble states of a print job using its properties
Friend Shared Function SpotTroubleUsingProperties2(ByVal theJob As PrintSystemJobInfo) As String
Dim returnString As String = ""If theJob.IsBlocked Then
returnString = "The job is blocked."
End If
If theJob.IsCompleted OrElse theJob.IsPrinted Then
returnString = "The job has finished. Have user recheck all output bins and be sure the correct printer is being checked."
End If
If theJob.IsDeleted OrElse theJob.IsDeleting Then
returnString = "The user or someone with administration rights to the queue has deleted the job. It must be resubmitted."
End If
If theJob.IsInError Then
returnString = "The job has errored."
End If
If theJob.IsOffline Then
returnString = "The printer is offline. Have user put it online with printer front panel."
End If
If theJob.IsPaperOut Then
returnString = "The printer is out of paper of the size required by the job. Have user add paper."
End IfIf theJob.IsPaused OrElse theJob.HostingPrintQueue.IsPaused Then
HandlePausedJob(theJob)
'HandlePausedJob is defined in the complete example.
End IfIf theJob.IsPrinting Then
returnString = "The job is printing now."
End If
If theJob.IsSpooling Then
returnString = "The job is spooling now."
End If
If theJob.IsUserInterventionRequired Then
returnString = "The printer needs human intervention."
End If
Return returnString
End Function 'end SpotTroubleUsingProperties'http://msdn.microsoft.com/en-us/library/aa970495.aspx
Friend Shared Sub ReportQueueAndJobAvailability(ByVal theJob As PrintSystemJobInfo, hostingQueue As PrintQueue)
'If Not (ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) AndAlso ReportAvailabilityAtThisTime(theJob)) Then
If Not (ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) AndAlso ReportAvailabilityAtThisTime(hostingQueue)) Then
If Not ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) Then
Console.WriteLine(vbLf & "That queue is not available at this time of day." & vbLf & "Jobs in the queue will start printing again at {0}", TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString())
' TimeConverter class is defined in the complete sample
End If'If Not ReportAvailabilityAtThisTime(theJob) Then
If Not ReportAvailabilityAtThisTime(hostingQueue) Then
Console.WriteLine(vbLf & "That job is set to print only between {0} and {1}", TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString(), TimeConverter.ConvertToLocalHumanReadableTime(theJob.UntilTimeOfDay).ToShortTimeString())
End If
Console.WriteLine(vbLf & "The job will begin printing as soon as it reaches the top of the queue after:")
If theJob.StartTimeOfDay > theJob.HostingPrintQueue.StartTimeOfDay Then
Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString())
Else
Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString())
End IfEnd If 'end if at least one is not available
End Sub 'end ReportQueueAndJobAvailability
'http://msdn.microsoft.com/en-us/library/aa970495.aspx
Private Shared Function ReportAvailabilityAtThisTime(ByVal pq As PrintQueue) As Boolean
Dim available As Boolean = True
If pq.StartTimeOfDay <> pq.UntilTimeOfDay Then ' If the printer is not available 24 hours a day
Dim utcNow As Date = Date.UtcNow
Dim utcNowAsMinutesAfterMidnight As Int32 = (utcNow.TimeOfDay.Hours * 60) + utcNow.TimeOfDay.Minutes' If now is not within the range of available times . . .
If Not ((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight) AndAlso (utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)) Then
available = False
End If
End If
Return available
End Function 'end ReportAvailabilityAtThisTime'http://msdn.microsoft.com/en-us/library/aa970495.aspx
Friend Class TimeConverter
' Convert time as minutes past UTC midnight into human readable time in local time zone.
Friend Shared Function ConvertToLocalHumanReadableTime(ByVal timeInMinutesAfterUTCMidnight As Int32) As Date
' Construct a UTC midnight object.
' Must start with current date so that the local Daylight Savings system, if any, will be taken into account.
Dim utcNow As Date = Date.UtcNow
Dim utcMidnight As New Date(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0, DateTimeKind.Utc)' Add the minutes passed into the method in order to get the intended UTC time.
Dim minutesAfterUTCMidnight As Double = CType(timeInMinutesAfterUTCMidnight, Double)
Dim utcTime As Date = utcMidnight.AddMinutes(minutesAfterUTCMidnight)' Convert to local time.
Dim localTime As Date = utcTime.ToLocalTime()Return localTime
End Function ' end ConvertToLocalHumanReadableTime
End Class 'end TimeConverter
'http://msdn.microsoft.com/en-us/library/system.printing.printsystemjobinfo.cancel(v=vs.110).aspx
Friend Shared Sub HandlePausedJob(ByVal theJob As PrintSystemJobInfo)
' If there's no good reason for the queue to be paused, resume it and
' give user choice to resume or cancel the job.
Console.WriteLine("The user or someone with administrative rights to the queue" & vbLf & "has paused the job or queue." & vbLf & "Resume the queue? (Has no effect if queue is not paused.)" & vbLf & "Enter ""Y"" to resume, otherwise press return: ")
Dim [resume] As String = Console.ReadLine()
If [resume] = "Y" Then
theJob.HostingPrintQueue.Resume()' It is possible the job is also paused. Find out how the user wants to handle that.
Console.WriteLine("Does user want to resume print job or cancel it?" & vbLf & "Enter ""Y"" to resume (any other key cancels the print job): ")
Dim userDecision As String = Console.ReadLine()
If userDecision = "Y" Then
theJob.Resume()
Else
theJob.Cancel()
End If
End If 'end if the queue should be resumedEnd Sub 'end HandlePausedJob
-
Hi
Ich habe etwas experimentiert.
Sowohl die erfragen des Status mit "winspool.drv" als auch PrintServer() -> GetPrintQueue bringen anscheinend das gleiche.
Bei
"NPIFC75A2 (HP Color LaserJet CP2025dn)" Drucker ist nicht angeschlossen, Status=Offline (richtig)
"EPSON SX430 Series" ohne eingelegtem Papier oder ausgeschaltet, Status=Ready (falsch)
auf dem Desktop erscheint eine entsprechende Meldung
"Canon Inkjet MP600 Printer" Drucker ist nicht angeschlossen , Status=Ready (falsch)
auf dem Desktop erscheint eine entsprechende Meldung
"HP LaserJet P2015 PCL6" Drucker ist nicht angeschlossen , Status=Offline (richtig)Lässt sich der Status denn nicht wirklich ermitteln?
Gruss Peter
-
Hallo Peter,
das Programm, in dem ich die Statusabfrage benutze, ist schon 14 Jahre alt und in VFP geschrieben. Damals ging es mir vor allem darum, auf den Rechnern der Anwender die genauen Geometrie-Werte der angeschlossenen Drucker zu erfragen, um Anwender-spezifische Reporte zu optimieren. Die Status-Abfrage war nur Beiwerk, funktionierte damals aber im Prinzip, jedoch auch nicht alle Bits auf allen Druckern.
Jetzt hab ich das Programm mal auf meinem aktuellen win8.1-System ausprobiert mit 3 angeschlossenen Druckern (davon allerdings 2 im Netzwerk) und ich bekomme keine brauchbaren Ergebnisse. Vermutlich wird inzwischen vieles nur noch über Geräte-spezifische Treiber-Funktionen geregelt. Ich glaube allerdings, dass ich kürzlich auf einem Rechner mit angeschlossenem Parallel-Port-Drucker noch eine funktionierende Status-Übermittlung gesehen habe.
In einem anderen Projekt, einem Kassenprogramm, bei dem es mir sehr wichtig ist, genau zu wissen, ob der Druck funktioniert, mache ich es anders: Ich checke einfach die Drucker-Queue. Wenn die vor dem Druck nicht leer ist, verweigert das Programm den Druck und die Verkaufsbuchung. Wenn die Queue nach dem Druck nach einer timeout-Zeit nicht leer ist, wird sie geleert und ebenfalls keine Verkaufsbuchung gemacht.
Gruß,
WiWo
-
Hallo Peter,
Du hast Dich vertrauenswürdiger Quellen bedient, nein zu sehen ist das nichts.
Aber: Was wird denn gemeldet wenn Du den/die PC's neu startest. Sagen wir mal Neustart des PC'S an dem der Epson angeschlossen ist + dem PC auf dem das Programm läuft.
Ich sehe 2 Ansätze:1. Die Hersteller/die Version dieses Druckertreibers bedienen die API nicht korrekt.
2. Der Status wird nicht sofort aktualisiert.
Falls nach dem Neustart der Status korrekt ist der vorher falsch war wäre das 2.
Grüße Alexander -
Hi WiWo,
da ich nicht weiss, wie die Umgebung auf dem das Programm installiert wird aussieht, d.h. welche Drucker dort vorhanden sind, bin ich auf dünnem Eis.
Ich bin erstaunt, dass es keine Funktion gibt, mit der man einfach und verlässlich den Druckerstatus abfragen kann.Würdest du mir noch sagen wie du die Drucker-Queue abfrägst.
Mit PrintQueue.GetPrintJobInfoCollection() ?Gruss Peter
-
Hi Alexander,
ich habe es mit dem Epson nochmals versucht.
Da sind keinerlei Informationen zu entlocken, ob Eingeschaltet, mit oder ohne Papier.Vielleicht liegt es ja an der Implementation des Druckertreibers, es ist ein sehr einfacher Drucker, vielleicht ist der Treiber dazu genau so einfach !?
Als ich an das Problem ging dachte ich, noch schnell eine Funktion aufrufen um den Druckerstatus abzufragen, jetzt ist das so ein murks.
Gruss Peter
-
Hallo Peter,
ich fürchte ich kann hier nicht weiterhelfen.
Ich tippe auch auf den Druckertreiber. Doch es ist nur geraten.
Ich finde allerdings Hinweise im Netz auf ein solches Verhalten.
Diverse Hersteller, u.a. EPSON, liefern eigene Software als Druckermonitor und ich finde Hinweise das diese dann mit dem Abfragen via WIN-API eben keine Informationen rausrücken.
Grüße Alexander