在大中型公司,在任何给定时间里,都可能发生由于卡纸、纸张用完或某些其他有问题而导致多台打印机无法工作的情况。 Microsoft .NET Framework 的 API 中公开的一组丰富的打印机属性提供一种方法,用于快速调查打印机状态。
以下是创建此类实用程序的主要步骤。
获取所有打印服务器的列表。
循环访问服务器以查询其打印队列。
在每一轮服务器循环访问过程中,循环访问所有服务器的队列并读取每个属性,这些属性可能指示队列当前不在工作。
以下代码是一系列代码段。 为简单起见,本示例假定存在通过 CRLF 分隔的打印服务器列表。 变量 fileOfPrintServers
是该文件的 StreamReader 对象。 由于每个服务器名称是在单独的一行上,因此对 ReadLine 的任何调用将获取下一服务器的名称并将 StreamReader 的光标移动到下一行的开头。
在外部循环中,代码会创建最新打印服务器的 PrintServer 对象,并指定应用程序需具有服务器的管理权限。
备注
如果有很多服务器,可以通过使用 PrintServer(String, String[], PrintSystemDesiredAccess) 构造函数来提高性能,这些构造函数仅初始化需要的属性。
然后,该示例使用 GetPrintQueues 来创建所有服务器队列的集合,并开始对其进行循环访问。 此内部循环包含一个分支结构,该结构对应于检查打印机状态的两种方法:
可读取类型为 PrintQueueStatus 的 QueueStatus 属性的标记。
可以读取每个相关属性,例如 IsOutOfPaper 和 IsPaperJammed。
此示例会演示这两种方法,系统会预先提示用户要使用哪种方法,且如果用户想要使用 QueueStatus 属性的标志,可回复“y”。 请参阅以下有关这两种方法的详细信息。
最后,会向用户显示结果。
// 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();
若要使用 QueueStatus 属性的标志检查打印机状态,请检查每个相关标志以查看是否对其进行了设置。 检查是否在一组位标志中设置了一个位的标准方法是执行一个逻辑 AND 运算,其中将该组标志作为一个操作数,将标志本身作为另一操作数。 由于该标志本身仅设置一个位,因此逻辑 AND 的结果至多为设置了该相同位。 若要查明事实是否如此,只需将逻辑 AND 的结果与标志本身进行比较。
对于已设置了其位的各个特性,代码会将一条通知添加到将向用户显示的最终报告中。 (下面会讨论代码结束时调用的 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);
}
若要使用各个属性检查打印机状态,只需读取各个属性,并将注释添加到最终报告,如果属性为 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
创建了 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. ";
}
}
}