Cómo: Detectar si un trabajo de impresión se puede imprimir en esta hora del día
Las colas de impresión no siempre están disponibles durante 24 horas al día. Disponen de propiedades de hora de inicio y finalización que se pueden establecer para que no estén disponibles a determinadas horas del día. Esta característica se puede usar, por ejemplo, para reservar una impresora para el uso exclusivo de un determinado departamento después de las 17:00. Ese departamento tendría una cola de servicio de impresora diferente a la que usan otros departamentos. La cola de los otros departamentos se establecería para que no estuviera disponible después de las 17:00, mientras que la cola del departamento preferido podría establecerse para estar disponible en todo momento.
Además, los propios trabajos de impresión se pueden establecer para que se puedan imprimir solo dentro de un intervalo de tiempo determinado.
Las clases PrintQueue y PrintSystemJobInfo expuestas en las API de Microsoft .NET Framework proporcionan un medio para comprobar de forma remota si un determinado trabajo de impresión puede imprimirse en una cola determinada en el momento actual.
Ejemplo
El siguiente ejemplo es una muestra que puede diagnosticar problemas con un trabajo de impresión.
Hay dos pasos principales para este tipo de función, como se indica a continuación.
Lea las propiedades de StartTimeOfDay y UntilTimeOfDay de la PrintQueue para determinar si la hora actual está entre ellas.
Lea las propiedades de StartTimeOfDay y UntilTimeOfDay de la PrintQueue para determinar si la hora actual está entre ellas.
Pero las complicaciones surgen del hecho de que estas propiedades no son objetos DateTime. En cambio, son objetos Int32 que expresan tanto la hora del día como el número de minutos desde la medianoche. Además, no se refiere a la medianoche en la zona horaria actual, sino a la medianoche UTC (Hora universal coordinada).
En el primer ejemplo de código presenta el método estático ReportQueueAndJobAvailability, que se pasa a los PrintSystemJobInfo y llama a los métodos de asistencia para determinar si el trabajo se puede imprimir en el momento actual y, si no es así, cuándo se puede imprimir. Observe que la PrintQueue no se pasa al método. Esto se debe a que el PrintSystemJobInfo incluye una referencia a la cola en su propiedad HostingPrintQueue.
Los métodos subordinados incluyen el método sobrecargado ReportAvailabilityAtThisTime que puede aceptar ya sea una PrintQueue o un PrintSystemJobInfo como parámetro. There is also a TimeConverter.ConvertToLocalHumanReadableTime. Todos estos métodos se analizan a continuación.
El método ReportQueueAndJobAvailability comienza comprobando si la cola o el trabajo de impresión no están disponibles en ese momento. Si alguno de ellos no está disponible, comprueba si la cola no está disponible. Si no está disponible, el método informa de este hecho y del momento en que la cola volverá a estar disponible. A continuación, comprueba el trabajo y, si no está disponible, informa del siguiente intervalo de tiempo en el que podrá imprimir. Finalmente, el método informa de la primera hora a la que se puede imprimir el trabajo. Esta es la más tardía de las dos horas siguientes.
El momento en que la cola de impresión está disponible de nuevo.
El momento en que el trabajo de impresión esté disponible de nuevo.
Cuando se informa de la hora del día, también se llama al método ToShortTimeString, ya que este método suprime los años, meses y días de la salida. No se puede restringir la disponibilidad de una cola de impresión o de un trabajo de impresión a determinados años, meses o días.
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
Las dos sobrecargas del método ReportAvailabilityAtThisTime son idénticas excepto por el tipo que se les pasa, por lo que solo se presenta la versión siguiente PrintQueue.
Nota:
El hecho de que los métodos sean idénticos excepto por el tipo plantea la cuestión de por qué la muestra no crea un método genérico ReportAvailabilityAtThisTime<T>. El motivo es que este método tendría que estar restringido a una clase que tenga las propiedades StartTimeOfDay y UntilTimeOfDay a las que el método llama, pero un método genérico solo se puede restringir a una sola clase y la única clase común a ambas PrintQueue y PrintSystemJobInfo en el árbol de herencia es la PrintSystemObject que no tiene dichas propiedades.
El método ReportAvailabilityAtThisTime (presentado en el ejemplo de código siguiente) comienza inicializando una variable sentinel Boolean a true
. Se restablecerá a false
, si la cola no está disponible.
A continuación, el método comprueba si los tiempos de inicio y "hasta" son idénticos. Si lo son, la cola siempre está disponible, por lo que el método devuelve true
.
Si la cola no está disponible todo el tiempo, el método usa la propiedad estática UtcNow para obtener la hora actual como objeto DateTime. (No necesitamos la hora local porque las propiedades StartTimeOfDay y UntilTimeOfDay están a su vez en la hora UTC).
Sin embargo, estas dos propiedades no son objetos DateTime. Están Int32 expresando la hora y el número de minutos después de la medianoche UTC. Por lo tanto, tenemos que convertir nuestro objeto DateTime en minutos después de la medianoche. Una vez hecho esto, el método simplemente comprueba si "ahora" está entre las horas de inicio y "hasta" de la cola, establece el sentinel falso si "ahora" no está entre las dos horas y devuelve el sentinel.
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
El método TimeConverter.ConvertToLocalHumanReadableTime (presentado en el ejemplo de código más abajo) no usa ningún método introducido con Microsoft .NET Framework, por lo que la explicación es breve. El método tiene una doble tarea de conversión: debe coger un número entero que exprese los minutos después de la medianoche y convertirlo a una hora legible y hacer la conversión a la hora local. Para ello, primero se crea un objeto DateTime que se establece en la medianoche UTC y luego usa el método AddMinutes para agregar los minutos que se han pasado al método. Esto devuelve una nueva DateTime que expresa la hora original a la que se ha pasado el método. A continuación, el método ToLocalTime convierte esto a la 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
Vea también
.NET Desktop feedback