在大中型公司,在任何给定时间里,都可能发生由于卡纸、纸张用完或某些其他有问题而导致多台打印机无法工作的情况。 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
    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();
    
    // 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.
                 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
    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.
                 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()
    

    若要使用 QueueStatus 属性的标志检查打印机状态,请检查每个相关标志以查看是否对其进行了设置。 检查是否在一组位标志中设置了一个位的标准方法是执行一个逻辑 AND 运算,其中将该组标志作为一个操作数,将标志本身作为另一操作数。 由于该标志本身仅设置一个位,因此逻辑 AND 的结果至多为设置了该相同位。 若要查明事实是否如此,只需将逻辑 AND 的结果与标志本身进行比较。 有关详细信息,请参阅 PrintQueueStatus& 运算符(C# 参考)FlagsAttribute

    对于已设置了其位的各个特性,代码会将一条通知添加到将向用户显示的最终报告中。 (下面会讨论代码结束时调用的 ReportAvailabilityAtThisTime 方法。)

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

    若要使用各个属性检查打印机状态,只需读取各个属性,并将注释添加到最终报告,如果属性为 true,将向用户显示最终报告。 (下面会讨论代码结束时调用的 ReportAvailabilityAtThisTime 方法。)

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

    创建了 ReportAvailabilityAtThisTime 方法,以应对需要确定队列在一天的当前时间是否可用的情况。

    如果 StartTimeOfDayUntilTimeOfDay 属性相等,该方法将不会执行任何操作;因为在这种情况下,打印机始终可用。 如果它们不同,则该方法将获取当前时间,该时间必须随后转换为午夜过后的总分钟数,因为 StartTimeOfDayUntilTimeOfDay 属性是表示午夜后分钟数的 Int32,而不是 DateTime 对象。 最后,该方法会检查当前时间是否介于开始时间和“截至”时间之间。

    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. ";
    
    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 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
    
  • StartTimeOfDay
  • UntilTimeOfDay
  • DateTime
  • PrintQueueStatus
  • FlagsAttribute
  • GetPrintQueues
  • PrintServer
  • LocalPrintServer
  • EnumeratedPrintQueueTypes
  • PrintQueue
  • &运算符(C# 引用)
  • WPF 中的文档
  •