下面是创建这种实用工具的主要步骤。
获取所有打印服务器的列表。
遍历各服务器以查询其打印队列。
在服务器遍历的每个处理过程中,遍历所有服务器的队列,并读取每个可能指示队列当前未工作的属性。
下面的代码由一系列代码段组成。为简单起见,此示例假设存在一个用 CRLF 分隔的打印服务器列表。变量fileOfPrintServers 是该文件的一个StreamReader 对象。由于每个服务器名称都在其各自的行上,因此每次调用ReadLine 时都会获取下一台服务器的名称,并将StreamReader 的游标移到下一行的开头。
在外部循环中,该代码为最后一台打印服务器创建一个PrintServer 对象,并指定该应用程序将对最后一台打印服务器具有管理权限。

注意
如果存在多台服务器,则可以通过使用PrintServer(String,String[], PrintSystemDesiredAccess) 构造函数来改进性能,这些构造函数仅对您将需要的属性进行初始化。

此示例随后使用GetPrintQueues 来创建一个包含所有服务器队列的集合,并开始遍历它们。内部循环包含一个与打印机状态的两种检查方法相对应的分支结构:
此示例对这两种方法均进行了演示,因此用户在这之前会被询问要使用哪种方法,如果用户希望使用QueueStatus 属性的标志,则可以回答“y”(是)。下面详细介绍了这两种方法。
最后,结果将呈现给用户。
C#
// 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 pqin 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 属性的标志来检查打印机状态,可以通过检查每个相关标志来查看它是否已经设置。如需检查是否在一组位标志中设置了某个位,标准方法是将这组标志作为一个操作数,将需要检查的标志本身作为另一个操作数,对它们执行逻辑“与”运算。由于该标志本身只设置了一个位,因此逻辑“与”运算的结果是至多设置了同一个位。若要确定是否设置了该位,只需将逻辑“与”运算的结果与该标志本身进行比较。有关更多信息,请参见PrintQueueStatus、& 运算符(C# 参考) 和FlagsAttribute。
对于每个设置了位的特性,该代码会在最终报告中添加一个将呈现给用户的通知(下面将讨论在该代码末尾处调用的ReportAvailabilityAtThisTime方法)。
C#
// Check for possible trouble states of a printer using the flags of the QueueStatus propertyinternalstaticvoid 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方法)。
C#
// Check for possible trouble states of a printer using its propertiesinternalstaticvoid 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 对象。最后,该方法将查看当前的时间是否介于开始时间和截止时间之间。
C#
privatestaticvoid 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