c# check printer status
in my application (Windows 7, VS2010) i have to decrement a credit counter after successfully printing an image. Anyway, before starting the entire process, i'd like to know about printer status in order to alert the user on paper out, paper jam and so on. Now, looking around i found several example that use Windows WMI but... never works. Using THIS snippet, for example, the printer status is always ready also if i remove the paper, open the cover... turn off the printer.
The printer status is always good also now, that i'm testing from office the printer that is comfortably turned off at home. have I to detonate the device by dynamite in order to have a printer error status?
This is the code i've used
ManagementObjectCollection MgmtCollection;
ManagementObjectSearcher MgmtSearcher;
//Perform the search for printers and return the listing as a collection
MgmtSearcher = new ManagementObjectSearcher("Select * from Win32_Printer");
MgmtCollection = MgmtSearcher.Get();
foreach (ManagementObject objWMI in MgmtCollection)
{
string name = objWMI["Name"].ToString().ToLower();
if (name.Equals(printerName.ToLower()))
{
int state = Int32.P开发者_开发知识库arse(objWMI["ExtendedPrinterStatus"].ToString());
if ((state == 1) || //Other
(state == 2) || //Unknown
(state == 7) || //Offline
(state == 9) || //error
(state == 11) //Not Available
)
{
throw new ApplicationException("hope you are finally offline");
}
state = Int32.Parse(objWMI["DetectedErrorState"].ToString());
if (state != 2) //No error
{
throw new ApplicationException("hope you are finally offline");
}
}
}
Where 'printerName' is received as parameter.
Thank you in advice.
The PrintQueue class in the System.Printing namespace is what you are after. It has many properties that give useful information about the status of the printer that it represents. Here are some examples;
var server = new LocalPrintServer();
PrintQueue queue = server.DefaultPrintQueue;
//various properties of printQueue
var isOffLine = queue.IsOffline;
var isPaperJam = queue.IsPaperJammed;
var requiresUser = queue.NeedUserIntervention;
var hasPaperProblem = queue.HasPaperProblem;
var isBusy = queue.IsBusy;
This is by no means a comprehensive list and remember that it is possible for the queue to have one or more of these statuses so you'll have to think about the order in which you handle them.
You don't say what version of .Net you're using, but since .Net 3.0 there has been some good printing functionality. I've used this and whilst I can't be sure that it reports all kinds of status levels, I've certainly seen messages such as 'Toner Low' for various printers etc.
PrinterDescription is a custom class, but you can see the properties its using.
http://msdn.microsoft.com/en-us/library/system.printing.aspx
PrintQueueCollection printQueues = null;
List<PrinterDescription> printerDescriptions = null;
// Get a list of available printers.
this.printServer = new PrintServer();
printQueues = this.printServer.GetPrintQueues(new[] { EnumeratedPrintQueueTypes.Local, EnumeratedPrintQueueTypes.Connections });
printerDescriptions = new List<PrinterDescription>();
foreach (PrintQueue printQueue in printQueues)
{
// 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. Another WPF issue that cannot be worked around.
if (printQueue.Name.ToUpperInvariant().Contains("ONENOTE") || printQueue.Name.ToUpperInvariant().Contains("REDIRECTED"))
{
continue;
}
string status = printQueue.QueueStatus.ToString();
try
{
PrinterDescription printerDescription = new PrinterDescription()
{
Name = printQueue.Name,
FullName = printQueue.FullName,
Status = status == Strings.Printing_PrinterStatus_NoneTxt ? Strings.Printing_PrinterStatus_ReadyTxt : status,
ClientPrintSchemaVersion = printQueue.ClientPrintSchemaVersion,
DefaultPrintTicket = printQueue.DefaultPrintTicket,
PrintCapabilities = printQueue.GetPrintCapabilities(),
PrintQueue = printQueue
};
printerDescriptions.Add(printerDescription);
}
catch (PrintQueueException ex)
{
// ... Logging removed
}
}
You can do this with printer queues as @mark_h pointed out above.
However, if your printer is not the default printer you need to load that printer's queue instead. What you need to do instead of calling server.DefaultPrintQueue
you would need to load the correct queue by calling GetPrintQueue()
then pass it the printer name and an empty string array.
//Get local print server
var server = new LocalPrintServer();
//Load queue for correct printer
PrintQueue queue = server.GetPrintQueue(PrinterName, new string[0] { });
//Check some properties of printQueue
bool isInError = queue.IsInError;
bool isOutOfPaper = queue.IsOutOfPaper;
bool isOffline = queue.IsOffline;
bool isBusy = queue.IsBusy;
The only solution that is reliable across all brands of printers is to use SNMP to query the number of pages printed and ensure that it matches the number of pages in the document sent.
SNMP OID for page count is 1.3.6.1.2.1.43.10.2.1.4
From my testing, every other strategy has had unreliable behavior (odd null reference exceptions when fetching the print queue repeatedly) or provided inaccurate status codes or page counts.
精彩评论