如何:确定此时是否可以打印一项打印作业

更新:2007 年 11 月

打印队列并非一天 24 小时始终可用。它们具有开始时间和结束时间的属性,可以对这些属性进行设置,使打印队列在一天的某些时间段不可用。例如,您可以使用此功能将打印机预定为在下午 5 点以后只能由某个部门使用。该部门将有一个队列使用打印机,该队列不同于其他部门的队列。其他部门的队列将设置为在下午 5 点以后不可用,而支持的部门的队列可以设置为随时可以使用。

另外,打印作业本身可以设置为仅在指定的时段内是可打印的。

Microsoft .NET Framework的 API 中公开的 PrintQueuePrintSystemJobInfo 类提供一种远程检查方式,用于检查给定的打印作业在当前时间是否可以在给定队列中打印。

示例

下面的示例摘自用于诊断打印作业问题的示例应用程序。有关完整示例,请参见诊断有问题的打印作业示例

下面是针对此类功能的两个主要步骤。

  1. 读取 PrintQueueStartTimeOfDayUntilTimeOfDay 属性,以确定当前时间是否介于这两个时间之间。

  2. 读取 PrintSystemJobInfoStartTimeOfDayUntilTimeOfDay 属性,以确定当前时间是否介于这两个时间之间。

但是问题变复杂了,因为这些属性不是 DateTime 对象,而是 Int32 对象,它们会将时间以午夜过后的分钟数表示。另外,此处指的不是当前时区的午夜,而是 UTC(协调世界时)午夜。

第一个代码示例提供静态方法 ReportQueueAndJobAvailability,会为该方法传递一个 PrintSystemJobInfo。该方法调用帮助器方法,以确定在当前时间是否可以打印该作业,如果不能,何时可以打印。请注意,不会将 PrintQueue 传递给该方法。这是因为 PrintSystemJobInfo 在其 HostingPrintQueue 属性中包括对队列的引用。

从属方法包括重载的 ReportAvailabilityAtThisTime 方法,它采用 PrintQueuePrintSystemJobInfo 作为参数。还存在一个 TimeConverter.ConvertToLocalHumanReadableTime。下面将讨论上述所有方法。

ReportQueueAndJobAvailability 方法首先检查队列或打印作业在当前时间是否可用。如果其中之一不可用,它将查看队列是否可用。如果队列不可用,该方法将报告此事实以及队列将再次可用的时间。然后,它检查作业,并查看其是否可用,随后报告可以打印作业的下一个时段。最后,此方法报告可以打印作业的最早时间。该时间是下列两个时间中较晚的一个时间。

  • 打印队列下次可用的时间。

  • 打印作业下次可用的时间。

当报告时间时,还会调用 ToShortTimeString 方法,因为此方法会从输出中取消年、月和日的显示。您不能将打印队列或打印作业的可用性限定为特定的年、月或日。

internal static void ReportQueueAndJobAvailability(PrintSystemJobInfo theJob)
{
    if (!(ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) && ReportAvailabilityAtThisTime(theJob)))
    {
        if (!ReportAvailabilityAtThisTime(theJob.HostingPrintQueue))
        {
            Console.WriteLine("\nThat queue is not available at this time of day." +
                "\nJobs in the queue will start printing again at {0}",
                 TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString());
            // TimeConverter class is defined in the complete sample
        }

        if (!ReportAvailabilityAtThisTime(theJob))
        {
            Console.WriteLine("\nThat job is set to print only between {0} and {1}",
                TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString(),
                TimeConverter.ConvertToLocalHumanReadableTime(theJob.UntilTimeOfDay).ToShortTimeString());
        }
        Console.WriteLine("\nThe job will begin printing as soon as it reaches the top of the queue after:");
        if (theJob.StartTimeOfDay > theJob.HostingPrintQueue.StartTimeOfDay)
        {
            Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString());
        }
        else
        {
            Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString());
        }

    }//end if at least one is not available

}//end ReportQueueAndJobAvailability
static void ReportQueueAndJobAvailability (PrintSystemJobInfo^ theJob) 
{
   if (!(ReportAvailabilityAtThisTime(theJob->HostingPrintQueue) && ReportAvailabilityAtThisTime(theJob)))
   {
      if (!ReportAvailabilityAtThisTime(theJob->HostingPrintQueue))
      {
         Console::WriteLine("\nThat queue is not available at this time of day." + "\nJobs in the queue will start printing again at {0}", TimeConverter::ConvertToLocalHumanReadableTime(theJob->HostingPrintQueue->StartTimeOfDay).ToShortTimeString());
         // TimeConverter class is defined in the complete sample
      }
      if (!ReportAvailabilityAtThisTime(theJob))
      {
         Console::WriteLine("\nThat job is set to print only between {0} and {1}", TimeConverter::ConvertToLocalHumanReadableTime(theJob->StartTimeOfDay).ToShortTimeString(), TimeConverter::ConvertToLocalHumanReadableTime(theJob->UntilTimeOfDay).ToShortTimeString());
      }
      Console::WriteLine("\nThe job will begin printing as soon as it reaches the top of the queue after:");
      if (theJob->StartTimeOfDay > theJob->HostingPrintQueue->StartTimeOfDay)
      {
         Console::WriteLine(TimeConverter::ConvertToLocalHumanReadableTime(theJob->StartTimeOfDay).ToShortTimeString());
      } else
      {
         Console::WriteLine(TimeConverter::ConvertToLocalHumanReadableTime(theJob->HostingPrintQueue->StartTimeOfDay).ToShortTimeString());
      }

   }
};

ReportAvailabilityAtThisTime 方法的两个重载是相同的(传递给它们的类型除外),所以下面仅给出 PrintQueue 版本。(有关完整示例,请参见诊断有问题的打印作业示例。)

说明:

这些方法除类型外都相同,这就引出了这样一个问题,为什么这个示例不创建泛型方法 ReportAvailabilityAtThisTime<T>。原因是这样一种方法将不得不限制为具有该方法调用的 StartTimeOfDayUntilTimeOfDay 属性的类,但是泛型方法仅可以限制为单一类,并且继承树中 PrintQueuePrintSystemJobInfo 的唯一共有类为 PrintSystemObject,不具有上述属性。

ReportAvailabilityAtThisTime 方法(如下面的代码示例中所示)首先将 Boolean sentinel 变量初始化为 true。如果队列不可用,该变量将被重置为 false。

接下来,该方法将查看开始时间与“截止”时间是否相同。如果相同,队列始终可用,所以该方法会返回 true。

如果队列始终不可用,该方法会使用静态 UtcNow 属性将当前时间获取为 DateTime 对象。(我们不需要本地时间,因为 StartTimeOfDayUntilTimeOfDay 属性本身就是 UTC 时间。)

不过,这两个属性不是 DateTime 对象,它们是 Int32,将时间表示为 UTC 午夜后的分钟数。因此我们需要将 DateTime 对象转换为午夜后的分钟数。完成后,该方法将仅查看“当前”时间是否介于队列的开始时间和“截止”时间之间,如果“当前”时间未介于这两个时间之间,则将 sentinel 设置为 false,并返回 sentinel。

private static Boolean ReportAvailabilityAtThisTime(PrintQueue pq)
{
    Boolean available = true;
    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)))
        {
            available = false;
        }
    }
    return available;
}//end ReportAvailabilityAtThisTime
static Boolean ReportAvailabilityAtThisTime (PrintQueue^ pq) 
{
   Boolean available = true;
   if (pq->StartTimeOfDay != pq->UntilTimeOfDay)
   {
      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)))
      {
         available = false;
      }
   }
   return available;
};

TimeConverter.ConvertToLocalHumanReadableTime 方法(如下面的代码示例中所示)不使用 Microsoft .NET Framework中引入的任何方法,所以下面将进行简单讨论。该方法有一个双重转换的任务:它必须用一个表示午夜后分钟数的整数,并将其转换为用户可以理解的时间;同时必须将其转换为本地时间。完成此任务的方法是:首先创建 DateTime 对象(设置为午夜 UTC),然后使用 AddMinutes 方法添加传递给该方法的分钟数。这将返回一个新的 DateTime,用以表示传递给该方法的初始时间。然后,ToLocalTime 方法将此时间转换为本地时间。

class TimeConverter
{
    // Convert time as minutes past UTC midnight into human readable time in local time zone.
    internal static DateTime ConvertToLocalHumanReadableTime(Int32 timeInMinutesAfterUTCMidnight)
    {
        // Construct a UTC midnight object.
        // Must start with current date so that the local Daylight Savings system, if any, will be taken into account.
        DateTime utcNow = DateTime.UtcNow; 
        DateTime utcMidnight = new DateTime(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0, DateTimeKind.Utc);

        // Add the minutes passed into the method in order to get the intended UTC time.
        Double minutesAfterUTCMidnight = (Double)timeInMinutesAfterUTCMidnight;
        DateTime utcTime = utcMidnight.AddMinutes(minutesAfterUTCMidnight);

        // Convert to local time.
        DateTime localTime = utcTime.ToLocalTime();

        return localTime;

    }// end ConvertToLocalHumanReadableTime

}//end TimeConverter class
private ref class TimeConverter {

internal: 
   static DateTime ConvertToLocalHumanReadableTime (Int32 timeInMinutesAfterUTCMidnight) 
   {
      // Construct a UTC midnight object.
      // Must start with current date so that the local Daylight Savings system, if any, will be taken into account.
      DateTime utcNow = DateTime::UtcNow;
      DateTime utcMidnight = DateTime(utcNow.Year, utcNow.Month, utcNow.Day, 0, 0, 0, DateTimeKind::Utc);

      // Add the minutes passed into the method in order to get the intended UTC time.
      Double minutesAfterUTCMidnight = ((Double)timeInMinutesAfterUTCMidnight);
      DateTime utcTime = utcMidnight.AddMinutes(minutesAfterUTCMidnight);

      // Convert to local time.
      DateTime localTime = utcTime.ToLocalTime();

      return localTime;
   };
};

请参见

概念

Windows Presentation Foundation 中的文档

打印概述

参考

DateTime

PrintSystemJobInfo

PrintQueue

其他资源

打印示例