С# проверить состояние принтера

в моем приложении (Windows 7, VS2010) я должен уменьшить счетчик кредитов после успешной печати изображения. В любом случае, прежде чем начать весь процесс, я хотел бы узнать о состоянии принтера, чтобы предупредить пользователя об отсутствии бумаги, замятии бумаги и так далее. Теперь, оглядываясь вокруг, я нашел несколько примеров, которые используют Windows WMI, но... никогда не работают. Используя ЭТУ фрагмент, например, статус принтера всегда готов также, если я удалить бумагу, откройте крышку... выключите принтер.

Состояние принтера всегда хорошее и сейчас, когда я тестирую из офиса принтер, который удобно выключен дома. я должен взорвать устройство динамитом, чтобы иметь статус ошибки принтера?

Это код, который я использовал

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.Parse(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");
        }

    }

}

Где "имя_принтера" принимается в качестве параметра.

Спасибо за совет.

Ответ 1

Вы не говорите, какую версию .Net вы используете, но с .Net 3.0 были некоторые хорошие функции печати. Я использовал это, и пока я не могу быть уверенным, что он сообщает о всех уровнях статуса, я, конечно, видел такие сообщения, как "Toner Low" для разных принтеров и т.д.

PrinterDescription - это настраиваемый класс, но вы можете увидеть его свойства.

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
            }
        }

Ответ 2

PrintQueue класс в System.Printing namespace - это то, что вам нужно. Он имеет много свойств, которые предоставляют полезную информацию о состоянии принтера, который он представляет. Вот несколько примеров:

        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;

Это далеко не полный список и помните, что очередь может иметь один или несколько из этих статусов, поэтому вам придется подумать о порядке, в котором вы их обрабатываете.

Ответ 3

Единственным надежным решением для всех марок принтеров является использование SNMP для запроса количества напечатанных страниц и обеспечения соответствия количества страниц в отправляемом документе.

SNMP OID для подсчета страниц - 1.3.6.1.2.1.43.10.2.1.4

Из моего тестирования любая другая стратегия имела ненадежное поведение (неоднозначные исключения для ссылки на выборку очереди печати) или предоставлены неточные коды состояния или количество страниц.

Ответ 4

Вы можете сделать это с очередями принтера, как @mark_h указано выше.

Однако, если ваш принтер не является принтером по умолчанию, вам нужно вместо этого загрузить очередь принтера. Что нужно сделать вместо вызова server.DefaultPrintQueue вам нужно загрузить правильную очередь, вызвав GetPrintQueue() затем передать ей имя принтера и пустой массив строк.

//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;