Практическое руководство. Удаленный опрос состояний принтеров
Обновлен: Ноябрь 2007
В любой момент времени в средних и крупных компаниях могут существовать несколько принтеров, не работающих из-за замятия бумаги, отсутствия бумаги или каких-то других проблемных ситуаций. Широкий набор свойств принтера, предоставленных в интерфейсах API-интерфейсы среды Microsoft .NET Framework, обеспечивает средства для выполнения быстрого опроса состояния принтеров.
Пример
Ниже приведены основные этапы по созданию служебной программы такого рода.
Получите список всех серверов печати.
Выполните цикл опроса серверов об их очередях печати.
В каждом проходе цикла через сервер просмотрите все очереди сервера и прочтите каждое свойство, которое может указывать на то, что очередь в данный момент не функционирует.
Приведенный ниже код представляет собой набор фрагментов кода. Полный пример содержится в разделе Пример опроса состояния принтеров.
Для простоты предполагается, что существует список серверов печати с разделителями CRLF. Переменная fileOfPrintServers является объектом StreamReader этого файла. Поскольку каждое имя сервера размещается в отдельной строке, любой вызов метода ReadLine возвращает имя следующего сервера и перемещает курсор StreamReader в начало следующей строки.
Во внешнем цикле в коде создается объект PrintServer для последнего сервера печати и указывается, что приложение должно обладать правами администратора сервера.
Примечание. |
---|
При наличии большого количества серверов можно повысить производительность с помощью конструкторов PrintServer(String, array<String[], PrintSystemDesiredAccess), которые инициализируют только необходимые свойства. |
В примере затем используется метод GetPrintQueues для создания коллекции всех очередей сервера и начинается проход по ним. Внутренний цикл содержит структуру перехода, соответствующую двум способам проверки состояния принтера:
можно прочесть флаги свойства QueueStatus типа PrintQueueStatus;
можно прочесть каждое соответствующее свойство, например IsOutOfPaper и IsPaperJammed.
В этом примере демонстрируются оба метода, так что пользователь имеет возможность заранее выбрать, какой метод следует использовать, и выбрать ответ «Y», если требуется использовать флаги свойства QueueStatus. Ниже приведены сведения об этих двух методах.
Наконец, результаты предоставляются пользователю.
// Survey queue status for every queue on every print server
String line;
String statusReport = "\n\nAny problem states are indicated below:\n\n";
while ((line = fileOfPrintServers.ReadLine()) != null)
{
PrintServer myPS = new PrintServer(line, PrintSystemDesiredAccess.AdministrateServer);
PrintQueueCollection myPrintQueues = myPS.GetPrintQueues();
statusReport = statusReport + "\n" + line;
foreach (PrintQueue pq in myPrintQueues)
{
pq.Refresh();
statusReport = statusReport + "\n\t" + pq.Name + ":";
if (useAttributesResponse == "y")
{
TroubleSpotter.SpotTroubleUsingQueueAttributes(ref statusReport, pq);
// TroubleSpotter class is defined in the complete example.
}
else
{
TroubleSpotter.SpotTroubleUsingProperties(ref statusReport, pq);
}
}// end for each print queue
}// end while list of print servers is not yet exhausted
fileOfPrintServers.Close();
Console.WriteLine(statusReport);
Console.WriteLine("\nPress Return to continue.");
Console.ReadLine();
// Survey queue status for every queue on every print server
System::String^ line;
System::String^ statusReport = "\n\nAny problem states are indicated below:\n\n";
while ((line = fileOfPrintServers->ReadLine()) != nullptr)
{
System::Printing::PrintServer^ myPS = gcnew System::Printing::PrintServer(line, PrintSystemDesiredAccess::AdministrateServer);
System::Printing::PrintQueueCollection^ myPrintQueues = myPS->GetPrintQueues();
statusReport = statusReport + "\n" + line;
for each (System::Printing::PrintQueue^ pq in myPrintQueues)
{
pq->Refresh();
statusReport = statusReport + "\n\t" + pq->Name + ":";
if (useAttributesResponse == "y")
{
TroubleSpotter::SpotTroubleUsingQueueAttributes(statusReport, pq);
// TroubleSpotter class is defined in the complete example.
} else
{
TroubleSpotter::SpotTroubleUsingProperties(statusReport, pq);
}
}
}
fileOfPrintServers->Close();
Console::WriteLine(statusReport);
Console::WriteLine("\nPress Return to continue.");
Console::ReadLine();
Чтобы проверить состояние принтера с помощью флагов свойства QueueStatus, выполняется проверка установки каждого соответствующего флага. Стандартным способом просмотра, установлен ли один бит в наборе битовых флагов, является применение логической операции AND с набором флагов в качестве одного операнда и самого флага — в качестве другого. Так как сам флаг имеет только одно битовое значение, результатом применения логического оператора AND является то, что в большинстве случаев устанавливается тот же самый бит. Чтобы узнать, справедливо ли это, просто сравните результат применения логического оператора AND и значение самого флага. Дополнительные сведения см. в разделах PrintQueueStatus, Оператор & (Справочник по C#) и FlagsAttribute.
Для каждого атрибута, для которого задано битовое значение, в коде добавляется уведомление для окончательного отчета, который будет предоставлен пользователю. (Метод ReportAvailabilityAtThisTime, вызываемый в конце кода, описан ниже.)
// Check for possible trouble states of a printer using the flags of the QueueStatus property
internal static void SpotTroubleUsingQueueAttributes(ref String statusReport, PrintQueue pq)
{
if ((pq.QueueStatus & PrintQueueStatus.PaperProblem) == PrintQueueStatus.PaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if ((pq.QueueStatus & PrintQueueStatus.NoToner) == PrintQueueStatus.NoToner)
{
statusReport = statusReport + "Is out of toner. ";
}
if ((pq.QueueStatus & PrintQueueStatus.DoorOpen) == PrintQueueStatus.DoorOpen)
{
statusReport = statusReport + "Has an open door. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Error) == PrintQueueStatus.Error)
{
statusReport = statusReport + "Is in an error state. ";
}
if ((pq.QueueStatus & PrintQueueStatus.NotAvailable) == PrintQueueStatus.NotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Offline) == PrintQueueStatus.Offline)
{
statusReport = statusReport + "Is off line. ";
}
if ((pq.QueueStatus & PrintQueueStatus.OutOfMemory) == PrintQueueStatus.OutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if ((pq.QueueStatus & PrintQueueStatus.PaperOut) == PrintQueueStatus.PaperOut)
{
statusReport = statusReport + "Is out of paper. ";
}
if ((pq.QueueStatus & PrintQueueStatus.OutputBinFull) == PrintQueueStatus.OutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if ((pq.QueueStatus & PrintQueueStatus.PaperJam) == PrintQueueStatus.PaperJam)
{
statusReport = statusReport + "Has a paper jam. ";
}
if ((pq.QueueStatus & PrintQueueStatus.Paused) == PrintQueueStatus.Paused)
{
statusReport = statusReport + "Is paused. ";
}
if ((pq.QueueStatus & PrintQueueStatus.TonerLow) == PrintQueueStatus.TonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if ((pq.QueueStatus & PrintQueueStatus.UserIntervention) == PrintQueueStatus.UserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}
// Check if queue is even available at this time of day
// The method below is defined in the complete example.
ReportAvailabilityAtThisTime(ref statusReport, pq);
}
internal:
// Check for possible trouble states of a printer using the flags of the QueueStatus property
static void SpotTroubleUsingQueueAttributes (System::String^% statusReport, System::Printing::PrintQueue^ pq)
{
if ((pq->QueueStatus & PrintQueueStatus::PaperProblem) == PrintQueueStatus::PaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if ((pq->QueueStatus & PrintQueueStatus::NoToner) == PrintQueueStatus::NoToner)
{
statusReport = statusReport + "Is out of toner. ";
}
if ((pq->QueueStatus & PrintQueueStatus::DoorOpen) == PrintQueueStatus::DoorOpen)
{
statusReport = statusReport + "Has an open door. ";
}
if ((pq->QueueStatus & PrintQueueStatus::Error) == PrintQueueStatus::Error)
{
statusReport = statusReport + "Is in an error state. ";
}
if ((pq->QueueStatus & PrintQueueStatus::NotAvailable) == PrintQueueStatus::NotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if ((pq->QueueStatus & PrintQueueStatus::Offline) == PrintQueueStatus::Offline)
{
statusReport = statusReport + "Is off line. ";
}
if ((pq->QueueStatus & PrintQueueStatus::OutOfMemory) == PrintQueueStatus::OutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if ((pq->QueueStatus & PrintQueueStatus::PaperOut) == PrintQueueStatus::PaperOut)
{
statusReport = statusReport + "Is out of paper. ";
}
if ((pq->QueueStatus & PrintQueueStatus::OutputBinFull) == PrintQueueStatus::OutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if ((pq->QueueStatus & PrintQueueStatus::PaperJam) == PrintQueueStatus::PaperJam)
{
statusReport = statusReport + "Has a paper jam. ";
}
if ((pq->QueueStatus & PrintQueueStatus::Paused) == PrintQueueStatus::Paused)
{
statusReport = statusReport + "Is paused. ";
}
if ((pq->QueueStatus & PrintQueueStatus::TonerLow) == PrintQueueStatus::TonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if ((pq->QueueStatus & PrintQueueStatus::UserIntervention) == PrintQueueStatus::UserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}
// Check if queue is even available at this time of day
// The method below is defined in the complete example.
ReportAvailabilityAtThisTime(statusReport, pq);
};
Чтобы проверить состояние принтера с помощью каждого свойства, необходимо прочесть каждое свойство и добавить уведомление в окончательный отчет, который будет предоставлен пользователю, если значение свойства — true. (Метод ReportAvailabilityAtThisTime, вызываемый в конце кода, описан ниже.)
// Check for possible trouble states of a printer using its properties
internal static void SpotTroubleUsingProperties(ref String statusReport, PrintQueue pq)
{
if (pq.HasPaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if (!(pq.HasToner))
{
statusReport = statusReport + "Is out of toner. ";
}
if (pq.IsDoorOpened)
{
statusReport = statusReport + "Has an open door. ";
}
if (pq.IsInError)
{
statusReport = statusReport + "Is in an error state. ";
}
if (pq.IsNotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if (pq.IsOffline)
{
statusReport = statusReport + "Is off line. ";
}
if (pq.IsOutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if (pq.IsOutOfPaper)
{
statusReport = statusReport + "Is out of paper. ";
}
if (pq.IsOutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if (pq.IsPaperJammed)
{
statusReport = statusReport + "Has a paper jam. ";
}
if (pq.IsPaused)
{
statusReport = statusReport + "Is paused. ";
}
if (pq.IsTonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if (pq.NeedUserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}
// Check if queue is even available at this time of day
// The following method is defined in the complete example.
ReportAvailabilityAtThisTime(ref statusReport, pq);
}//end SpotTroubleUsingProperties
internal:
// Check for possible trouble states of a printer using its properties
static void SpotTroubleUsingProperties (System::String^% statusReport, System::Printing::PrintQueue^ pq)
{
if (pq->HasPaperProblem)
{
statusReport = statusReport + "Has a paper problem. ";
}
if (!(pq->HasToner))
{
statusReport = statusReport + "Is out of toner. ";
}
if (pq->IsDoorOpened)
{
statusReport = statusReport + "Has an open door. ";
}
if (pq->IsInError)
{
statusReport = statusReport + "Is in an error state. ";
}
if (pq->IsNotAvailable)
{
statusReport = statusReport + "Is not available. ";
}
if (pq->IsOffline)
{
statusReport = statusReport + "Is off line. ";
}
if (pq->IsOutOfMemory)
{
statusReport = statusReport + "Is out of memory. ";
}
if (pq->IsOutOfPaper)
{
statusReport = statusReport + "Is out of paper. ";
}
if (pq->IsOutputBinFull)
{
statusReport = statusReport + "Has a full output bin. ";
}
if (pq->IsPaperJammed)
{
statusReport = statusReport + "Has a paper jam. ";
}
if (pq->IsPaused)
{
statusReport = statusReport + "Is paused. ";
}
if (pq->IsTonerLow)
{
statusReport = statusReport + "Is low on toner. ";
}
if (pq->NeedUserIntervention)
{
statusReport = statusReport + "Needs user intervention. ";
}
// Check if queue is even available at this time of day
// The following method is defined in the complete example.
ReportAvailabilityAtThisTime(statusReport, pq);
};
Метод ReportAvailabilityAtThisTime создан для того, чтобы при необходимости определить, доступна ли очередь в текущий момент времени.
Метод не выполняет действий, если свойства StartTimeOfDay и UntilTimeOfDay равны; так как в этом случае принтер доступен в любое время. Если они отличаются, метод получает значение текущего времени, которое затем должно быть преобразовано в количество минут, прошедших после полуночи, потому что свойства StartTimeOfDay и UntilTimeOfDay являются типами Int32, представляющими минуты после полуночи, а не объектами DateTime. Наконец, метод проверяет, попадает ли текущее время в период между временем начала и «до тех пор, пока».
private static void ReportAvailabilityAtThisTime(ref String statusReport, PrintQueue pq)
{
if (pq.StartTimeOfDay != pq.UntilTimeOfDay) // If the printer is not available 24 hours a day
{
DateTime utcNow = DateTime.UtcNow;
Int32 utcNowAsMinutesAfterMidnight = (utcNow.TimeOfDay.Hours * 60) + utcNow.TimeOfDay.Minutes;
// If now is not within the range of available times . . .
if (!((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight)
&&
(utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)))
{
statusReport = statusReport + " Is not available at this time of day. ";
}
}
}
private:
static void ReportAvailabilityAtThisTime (System::String^% statusReport, System::Printing::PrintQueue^ pq)
{
if (pq->StartTimeOfDay != pq->UntilTimeOfDay)
{
System::DateTime utcNow = DateTime::UtcNow;
System::Int32 utcNowAsMinutesAfterMidnight = (utcNow.TimeOfDay.Hours * 60) + utcNow.TimeOfDay.Minutes;
// If now is not within the range of available times . . .
if (!((pq->StartTimeOfDay < utcNowAsMinutesAfterMidnight) && (utcNowAsMinutesAfterMidnight < pq->UntilTimeOfDay)))
{
statusReport = statusReport + " Is not available at this time of day. ";
}
}
};
См. также
Основные понятия
Документы в Windows Presentation Foundation