Como descobrir se um trabalho de impressão pode ser impresso a esta hora do dia

Filas de impressão não estão sempre disponíveis 24 horas por dia. Eles têm propriedades de tempo de início e término que podem ser definidas para torná-las indisponíveis em determinados momentos do dia. Esse recurso pode ser usado, por exemplo, para reservar uma impressora para uso exclusivo de um determinado departamento após as 17h. Esse departamento teria uma fila diferente na impressora do que a que outros departamentos usam. A fila para os outros departamentos seria definida como indisponível após as 17h, enquanto a fila para o departamento favorecido poderia ser definida para estar sempre disponível.

Além disso, os próprios trabalhos de impressão podem ser definidos para serem impressos apenas dentro de um período especificado.

As PrintQueue classes e PrintSystemJobInfo expostas nas APIs do Microsoft .NET Framework fornecem um meio para verificar remotamente se um determinado trabalho de impressão pode imprimir em uma determinada fila no momento atual.

Exemplo

O exemplo a seguir é um exemplo que pode diagnosticar problemas com um trabalho de impressão.

Há duas etapas principais para esse tipo de função, da seguinte maneira.

  1. Leia as StartTimeOfDay propriedades e UntilTimeOfDay do PrintQueue para determinar se a hora atual está entre eles.

  2. Leia as StartTimeOfDay propriedades e UntilTimeOfDay do PrintSystemJobInfo para determinar se a hora atual está entre eles.

Mas as complicações surgem do fato de que essas propriedades não DateTime são objetos. Em vez disso, são Int32 objetos que expressam a hora do dia como o número de minutos desde a meia-noite. Além disso, não se trata de meia-noite no fuso horário atual, mas meia-noite no UTC (Tempo Universal Coordenado).

O primeiro exemplo de código apresenta o método estático ReportQueueAndJobAvailability, que é passado a PrintSystemJobInfo e chama métodos auxiliares para determinar se o trabalho pode imprimir no momento atual e, se não, quando ele pode imprimir. Observe que a PrintQueue não é passado para o método. Isso ocorre porque o PrintSystemJobInfo inclui uma referência à fila em sua HostingPrintQueue propriedade.

Os métodos subordinados incluem o método ReportAvailabilityAtThisTime sobrecarregado que pode ter um ou um PrintQueuePrintSystemJobInfo como parâmetro. Também há um TimeConverter.ConvertToLocalHumanReadableTime. Todos esses métodos são discutidos abaixo.

O método ReportQueueAndJobAvailability começa verificando se a fila ou o trabalho de impressão está indisponível no momento. Se um deles estiver indisponível, ele verificará se a fila está indisponível. Se ela não estiver disponível, o método relatará esse fato e a hora em que a fila estará disponível novamente. Em seguida, ele verifica o trabalho e, se ele estiver indisponível, relatará o próximo intervalo em que ela pode ser impressa. Por fim, o método relata o horário mais próximo em que o trabalho pode ser impresso. Ele é o segundo dos dois horários a seguir.

  • A hora em que a fila de impressão ficará disponível.

  • A hora em que o trabalho de impressão ficará disponível.

Ao relatar horas do dia, o ToShortTimeString método também é chamado porque esse método suprime os anos, meses e dias da saída. Você não pode restringir a disponibilidade de uma fila de impressão ou de um trabalho de impressão para dias, meses ou anos específicos.

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());
      }

   }
};
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
Friend Shared Sub ReportQueueAndJobAvailability(ByVal theJob As PrintSystemJobInfo)
    If Not(ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) AndAlso ReportAvailabilityAtThisTime(theJob)) Then
        If Not ReportAvailabilityAtThisTime(theJob.HostingPrintQueue) Then
            Console.WriteLine(vbLf & "That queue is not available at this time of day." & vbLf & "Jobs in the queue will start printing again at {0}", TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString())
            ' TimeConverter class is defined in the complete sample
        End If

        If Not ReportAvailabilityAtThisTime(theJob) Then
            Console.WriteLine(vbLf & "That job is set to print only between {0} and {1}", TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString(), TimeConverter.ConvertToLocalHumanReadableTime(theJob.UntilTimeOfDay).ToShortTimeString())
        End If
        Console.WriteLine(vbLf & "The job will begin printing as soon as it reaches the top of the queue after:")
        If theJob.StartTimeOfDay > theJob.HostingPrintQueue.StartTimeOfDay Then
            Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.StartTimeOfDay).ToShortTimeString())
        Else
            Console.WriteLine(TimeConverter.ConvertToLocalHumanReadableTime(theJob.HostingPrintQueue.StartTimeOfDay).ToShortTimeString())
        End If

    End If 'end if at least one is not available

End Sub

As duas sobrecargas do método ReportAvailabilityAtThisTime são idênticas, exceto pelo tipo passado para elas, portanto, somente a PrintQueue versão é apresentada abaixo.

Observação

O fato de que os métodos são idênticos, exceto para o tipo levanta a questão de por que o exemplo não cria um método genérico ReportAvailabilityAtThisTime<T>. A razão é que tal método teria que ser restrito a uma classe que tem as propriedades StartTimeOfDay e UntilTimeOfDay que o método chama, mas um método genérico só pode ser restrito a uma única classe e a única classe comum a ambos PrintQueue e PrintSystemJobInfo na árvore de herança é PrintSystemObject que não tem tais propriedades.

O método ReportAvailabilityAtThisTime (apresentado no exemplo de código abaixo) começa inicializando uma Boolean variável sentinela para true. Ele será redefinido para false se a fila não estiver disponível.

Em seguida, o método verifica se as horas de início e "até" são idênticas. Se forem, a fila sempre estará disponível, então o método retornará true.

Se a fila não estiver disponível o tempo todo, o método usará a propriedade static UtcNow para obter a hora atual como um DateTime objeto. (Não precisamos da hora local porque as StartTimeOfDay propriedades e UntilTimeOfDay estão em si na hora UTC.)

No entanto, essas duas propriedades não DateTime são objetos. Eles estão Int32expressando o tempo como o número de minutos após a meia-noite. Então, temos que converter nosso DateTime objeto para minutos depois da meia-noite. Quando isso é feito, o método simplesmente verifica se "agora" está entre as horas de início da fila e "até", define a sentinela como falsa caso "agora" não esteja entre as duas horas e retorna a sentinela.

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;
};
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
Private Shared Function ReportAvailabilityAtThisTime(ByVal pq As PrintQueue) As Boolean
    Dim available As Boolean = True
    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
            available = False
        End If
    End If
    Return available
End Function 'end ReportAvailabilityAtThisTime

O método TimeConverter.ConvertToLocalHumanReadableTime (apresentado no exemplo de código abaixo) não usa nenhum método introduzido com o Microsoft .NET Framework, portanto, a discussão é breve. O método tem uma tarefa de conversão dupla: ele deve receber um inteiro expressando minutos após a meia-noite e convertê-lo em um horário legível, e precisa convertê-lo no horário local. Ele faz isso criando primeiro um DateTime objeto que é definido como meia-noite UTC e, em seguida, usa o método para adicionar os minutos que foram passados para o AddMinutes método. Isso retorna uma nova DateTime expressão da hora original que foi passada para o método. Em ToLocalTime seguida, o método converte isso para a hora local.

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;
   };
};
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
Friend Class TimeConverter
    ' Convert time as minutes past UTC midnight into human readable time in local time zone.
    Friend Shared Function ConvertToLocalHumanReadableTime(ByVal timeInMinutesAfterUTCMidnight As Int32) As Date
        ' Construct a UTC midnight object.
        ' Must start with current date so that the local Daylight Savings system, if any, will be taken into account.
        Dim utcNow As Date = Date.UtcNow
        Dim utcMidnight As New Date(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.
        Dim minutesAfterUTCMidnight As Double = CType(timeInMinutesAfterUTCMidnight, Double)
        Dim utcTime As Date = utcMidnight.AddMinutes(minutesAfterUTCMidnight)

        ' Convert to local time.
        Dim localTime As Date = utcTime.ToLocalTime()

        Return localTime

    End Function ' end ConvertToLocalHumanReadableTime

End Class

Confira também