如何:远程调查打印机的状态

在任何给定时间,大中型公司都可能会有多台打印机由于夹纸、缺纸或者某种其他异常情况而无法工作。 Microsoft .NET Framework的 APIs 中公开了一组丰富的打印机属性,通过这些属性可以快速调查打印机的状态。

示例

下面是创建这种实用工具的主要步骤。

  1. 获取所有打印服务器的列表。

  2. 遍历各服务器以查询其打印队列。

  3. 在服务器遍历的每个处理过程中,遍历所有服务器的队列,并读取每个可能指示队列当前未工作的属性。

下面的代码由一系列代码段组成。 为简单起见,此示例假设存在一个用 CRLF 分隔的打印服务器列表。 变量 fileOfPrintServers 是该文件的一个 StreamReader 对象。 由于每个服务器名称都在其各自的行上,因此每次调用 ReadLine 时都会获取下一台服务器的名称,并将 StreamReader 的游标移到下一行的开头。

在外部循环中,该代码为最后一台打印服务器创建一个 PrintServer 对象,并指定该应用程序将对最后一台打印服务器具有管理权限。

注意注意

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

此示例随后使用 GetPrintQueues 来创建一个包含所有服务器队列的集合,并开始遍历它们。 内部循环包含一个与打印机状态的两种检查方法相对应的分支结构:

此示例对这两种方法均进行了演示,因此用户在这之前会被询问要使用哪种方法,如果用户希望使用 QueueStatus 属性的标志,则可以回答“y”(是)。 下面详细介绍了这两种方法。

最后,结果将呈现给用户。

            ' Survey queue status for every queue on every print server
            Dim line As String
            Dim statusReport As String = vbLf & vbLf & "Any problem states are indicated below:" & vbLf & vbLf
            line = fileOfPrintServers.ReadLine()
            Do While line IsNot Nothing
                 Dim myPS As New PrintServer(line, PrintSystemDesiredAccess.AdministrateServer)
                 Dim myPrintQueues As PrintQueueCollection = myPS.GetPrintQueues()
                 statusReport = statusReport & vbLf & line
                 For Each pq As PrintQueue In myPrintQueues
                     pq.Refresh()
                     statusReport = statusReport & vbLf & vbTab & pq.Name & ":"
                     If useAttributesResponse = "y" Then
                         TroubleSpotter.SpotTroubleUsingQueueAttributes(statusReport, pq)
                         ' TroubleSpotter class is defined in the complete example.
                     Else
                         TroubleSpotter.SpotTroubleUsingProperties(statusReport, pq)
                     End If

                 Next pq ' end for each print queue

                line = fileOfPrintServers.ReadLine()
            Loop ' end while list of print servers is not yet exhausted

            fileOfPrintServers.Close()
            Console.WriteLine(statusReport)
            Console.WriteLine(vbLf & "Press Return to continue.")
            Console.ReadLine()

// 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 属性的标志来检查打印机状态,可以通过检查每个相关标志来查看它是否已经设置。 如需检查是否在一组位标志中设置了某个位,标准方法是将这组标志作为一个操作数,将需要检查的标志本身作为另一个操作数,对它们执行逻辑“与”运算。 由于该标志本身只设置了一个位,因此逻辑“与”运算的结果是至多设置了同一个位。 若要确定是否设置了该位,只需将逻辑“与”运算的结果与该标志本身进行比较。 有关更多信息,请参见 PrintQueueStatus& 运算符(C# 参考)FlagsAttribute

对于每个设置了位的特性,该代码会在最终报告中添加一个将呈现给用户的通知 (下面将讨论在该代码末尾处调用的 ReportAvailabilityAtThisTime 方法)。

        ' Check for possible trouble states of a printer using the flags of the QueueStatus property
        Friend Shared Sub SpotTroubleUsingQueueAttributes(ByRef statusReport As String, ByVal pq As PrintQueue)
            If (pq.QueueStatus And PrintQueueStatus.PaperProblem) = PrintQueueStatus.PaperProblem Then
                statusReport = statusReport & "Has a paper problem. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.NoToner) = PrintQueueStatus.NoToner Then
                statusReport = statusReport & "Is out of toner. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.DoorOpen) = PrintQueueStatus.DoorOpen Then
                statusReport = statusReport & "Has an open door. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.Error) = PrintQueueStatus.Error Then
                statusReport = statusReport & "Is in an error state. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.NotAvailable) = PrintQueueStatus.NotAvailable Then
                statusReport = statusReport & "Is not available. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.Offline) = PrintQueueStatus.Offline Then
                statusReport = statusReport & "Is off line. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.OutOfMemory) = PrintQueueStatus.OutOfMemory Then
                statusReport = statusReport & "Is out of memory. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.PaperOut) = PrintQueueStatus.PaperOut Then
                statusReport = statusReport & "Is out of paper. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.OutputBinFull) = PrintQueueStatus.OutputBinFull Then
                statusReport = statusReport & "Has a full output bin. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.PaperJam) = PrintQueueStatus.PaperJam Then
                statusReport = statusReport & "Has a paper jam. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.Paused) = PrintQueueStatus.Paused Then
                statusReport = statusReport & "Is paused. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.TonerLow) = PrintQueueStatus.TonerLow Then
                statusReport = statusReport & "Is low on toner. "
            End If
            If (pq.QueueStatus And PrintQueueStatus.UserIntervention) = PrintQueueStatus.UserIntervention Then
                statusReport = statusReport & "Needs user intervention. "
            End If

            ' Check if queue is even available at this time of day
            ' The method below is defined in the complete example.
            ReportAvailabilityAtThisTime(statusReport, pq)
        End Sub
// 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
        Friend Shared Sub SpotTroubleUsingProperties(ByRef statusReport As String, ByVal pq As PrintQueue)
            If pq.HasPaperProblem Then
                statusReport = statusReport & "Has a paper problem. "
            End If
            If Not(pq.HasToner) Then
                statusReport = statusReport & "Is out of toner. "
            End If
            If pq.IsDoorOpened Then
                statusReport = statusReport & "Has an open door. "
            End If
            If pq.IsInError Then
                statusReport = statusReport & "Is in an error state. "
            End If
            If pq.IsNotAvailable Then
                statusReport = statusReport & "Is not available. "
            End If
            If pq.IsOffline Then
                statusReport = statusReport & "Is off line. "
            End If
            If pq.IsOutOfMemory Then
                statusReport = statusReport & "Is out of memory. "
            End If
            If pq.IsOutOfPaper Then
                statusReport = statusReport & "Is out of paper. "
            End If
            If pq.IsOutputBinFull Then
                statusReport = statusReport & "Has a full output bin. "
            End If
            If pq.IsPaperJammed Then
                statusReport = statusReport & "Has a paper jam. "
            End If
            If pq.IsPaused Then
                statusReport = statusReport & "Is paused. "
            End If
            If pq.IsTonerLow Then
                statusReport = statusReport & "Is low on toner. "
            End If
            If pq.NeedUserIntervention Then
                statusReport = statusReport & "Needs user intervention. "
            End If

            ' Check if queue is even available at this time of day
            ' The following method is defined in the complete example.
            ReportAvailabilityAtThisTime(statusReport, pq)

        End Sub 'end SpotTroubleUsingProperties
// 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 Shared Sub ReportAvailabilityAtThisTime(ByRef statusReport As String, ByVal pq As PrintQueue)
            If pq.StartTimeOfDay <> pq.UntilTimeOfDay Then ' If the printer is not available 24 hours a day
        Dim utcNow As Date = Date.UtcNow
        Dim utcNowAsMinutesAfterMidnight As Int32 = (utcNow.TimeOfDay.Hours * 60) + utcNow.TimeOfDay.Minutes

                ' If now is not within the range of available times . . .
                If Not((pq.StartTimeOfDay < utcNowAsMinutesAfterMidnight) AndAlso (utcNowAsMinutesAfterMidnight < pq.UntilTimeOfDay)) Then
                    statusReport = statusReport & " Is not available at this time of day. "
                End If
            End If
        End Sub
        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. ";
         }
      }
   };

请参见

参考

StartTimeOfDay

UntilTimeOfDay

DateTime

PrintQueueStatus

& 运算符(C# 参考)

FlagsAttribute

GetPrintQueues

PrintServer

LocalPrintServer

EnumeratedPrintQueueTypes

PrintQueue

概念

WPF 中的文档

打印概述