Nota:
El acceso a esta página requiere autorización. Puede intentar iniciar sesión o cambiar directorios.
El acceso a esta página requiere autorización. Puede intentar cambiar los directorios.
Actualización: noviembre 2007
Los administradores de red con frecuencia tienen que ocuparse de las quejas de los usuarios sobre trabajos de impresión que no se imprimen o lo hacen con lentitud. El conjunto enriquecido de propiedades de trabajos de impresión expuesto en las API de Microsoft .NET Framework proporciona un medio para realizar un diagnóstico remoto rápido de los trabajos de impresión.
Ejemplo
Los pasos principales para crear este tipo de utilidad son los siguientes.
Identifique el trabajo de impresión que provoca la queja del usuario. Con frecuencia, los usuarios no lo pueden hacer con precisión. Es posible que no sepan el nombre de los servidores de impresión o de las impresoras. Puede que describan la ubicación de la impresora con una terminología distinta a la utilizada al establecer su propiedad Location. En consecuencia, es conveniente generar una lista de trabajos del usuario actualmente enviados. Si hay más de uno, entonces puede utilizarse la comunicación entre el usuario y el administrador del sistema de impresión para determinar con precisión qué trabajo es el que presenta problemas. Para ello, proceda como sigue.
Obtenga una lista de todos los servidores de impresión.
Recorra en bucle los servidores para consultar sus colas de impresión.
En cada pasada del bucle de servidor, recorra en bucle todas las colas del servidor para consultar sus trabajos.
Dentro de cada pasada del bucle de cola, recorra en bucle sus trabajos y recolecte la información identificativa sobre aquéllos que ha enviado el usuario que se queja.
Una vez identificado el trabajo de impresión problemático, examine las propiedades pertinentes para ver cuál puede ser el problema. Por ejemplo, ¿el trabajo se encuentra en un estado de error? o ¿la impresora correspondiente se ha desconectado antes de imprimir el trabajo?
El código siguiente consiste en una serie de ejemplos de código. Para obtener el ejemplo completo, consulte Ejemplo Diagnose Problematic Print Job.
El primer ejemplo de código contiene el bucle que recorre las colas de impresión. (Paso 1c anterior.) La variable myPrintQueues es el objeto PrintQueueCollection correspondiente al servidor de impresión actual.
El ejemplo de código comienza actualizando el objeto de cola de impresión actual mediante PrintQueue.Refresh. De este modo, se asegura de que las propiedades del objeto se corresponden con precisión al estado de la impresora física que representan. A continuación, la aplicación obtiene la colección de trabajos de impresión que se encuentran en este momento en la cola de impresión, mediante GetPrintJobInfoCollection.
Luego, la aplicación recorre en bucle la colección PrintSystemJobInfo y compara cada propiedad Submitter con el alias del usuario que ha presentado la queja. Si coinciden, la aplicación agrega información identificativa sobre el trabajo a la cadena que se presentará. (Las variables jobList y userName se inicializan anteriormente en la aplicación.)
foreach (PrintQueue pq in myPrintQueues)
{
pq.Refresh();
PrintJobInfoCollection jobs = pq.GetPrintJobInfoCollection();
foreach (PrintSystemJobInfo job in jobs)
{
// Since the user may not be able to articulate which job is problematic,
// present information about each job the user has submitted.
if (job.Submitter == userName)
{
atLeastOne = true;
jobList = jobList + "\nServer:" + line;
jobList = jobList + "\n\tQueue:" + pq.Name;
jobList = jobList + "\n\tLocation:" + pq.Location;
jobList = jobList + "\n\t\tJob: " + job.JobName + " ID: " + job.JobIdentifier;
}
}// end for each print job
}// end for each print queue
for each (PrintQueue^ pq in myPrintQueues)
{
pq->Refresh();
PrintJobInfoCollection^ jobs = pq->GetPrintJobInfoCollection();
for each (PrintSystemJobInfo^ job in jobs)
{
// Since the user may not be able to articulate which job is problematic,
// present information about each job the user has submitted.
if (job->Submitter == userName)
{
atLeastOne = true;
jobList = jobList + "\nServer:" + line;
jobList = jobList + "\n\tQueue:" + pq->Name;
jobList = jobList + "\n\tLocation:" + pq->Location;
jobList = jobList + "\n\t\tJob: " + job->JobName + " ID: " + job->JobIdentifier;
}
}
}
En el ejemplo de código siguiente se continúa con la aplicación en el paso 2. (Consulte lo anterior.) Se ha identificado el trabajo problemático y la aplicación solicita la información que lo identificará. A partir de esta información, crea los objetos PrintServer, PrintQueue y PrintSystemJobInfo.
En este punto, la aplicación contiene una estructura de bifurcación que corresponde a las dos maneras de comprobar el estado de un trabajo de impresión:
Puede leer los marcadores de la propiedad JobStatus, que es del tipo PrintJobStatus.
Puede leer cada propiedad pertinente, como IsBlocked y IsInError.
En este ejemplo se muestran ambos métodos, de modo que previamente se ha preguntado al usuario qué método desea utilizar y este ha respondido con "Y" (Sí) si desea utilizar los marcadores de la propiedad JobStatus. Consulte más adelante los detalles de los dos métodos. Por último, la aplicación utiliza un método denominado ReportQueueAndJobAvailability para informar de si el trabajo se puede imprimir en este momento de día. Este método se describe en Cómo: Detectar si un trabajo de impresión se puede imprimir en esta hora del día.
// When the problematic print job has been identified, enter information about it.
Console.Write("\nEnter the print server hosting the job (including leading slashes \\\\): " +
"\n(press Return for the current computer \\\\{0}): ", Environment.MachineName);
String pServer = Console.ReadLine();
if (pServer == "")
{
pServer = "\\\\" +Environment.MachineName;
}
Console.Write("\nEnter the print queue hosting the job: ");
String pQueue = Console.ReadLine();
Console.Write("\nEnter the job ID: ");
Int16 jobID = Convert.ToInt16(Console.ReadLine());
// Create objects to represent the server, queue, and print job.
PrintServer hostingServer = new PrintServer(pServer, PrintSystemDesiredAccess.AdministrateServer);
PrintQueue hostingQueue = new PrintQueue(hostingServer, pQueue, PrintSystemDesiredAccess.AdministratePrinter);
PrintSystemJobInfo theJob = hostingQueue.GetJob(jobID);
if (useAttributesResponse == "Y")
{
TroubleSpotter.SpotTroubleUsingJobAttributes(theJob);
// TroubleSpotter class is defined in the complete example.
}
else
{
TroubleSpotter.SpotTroubleUsingProperties(theJob);
}
TroubleSpotter.ReportQueueAndJobAvailability(theJob);
// When the problematic print job has been identified, enter information about it.
Console::Write("\nEnter the print server hosting the job (including leading slashes \\\\): " + "\n(press Return for the current computer \\\\{0}): ", Environment::MachineName);
String^ pServer = Console::ReadLine();
if (pServer == "")
{
pServer = "\\\\" + Environment::MachineName;
}
Console::Write("\nEnter the print queue hosting the job: ");
String^ pQueue = Console::ReadLine();
Console::Write("\nEnter the job ID: ");
Int16 jobID = Convert::ToInt16(Console::ReadLine());
// Create objects to represent the server, queue, and print job.
PrintServer^ hostingServer = gcnew PrintServer(pServer, PrintSystemDesiredAccess::AdministrateServer);
PrintQueue^ hostingQueue = gcnew PrintQueue(hostingServer, pQueue, PrintSystemDesiredAccess::AdministratePrinter);
PrintSystemJobInfo^ theJob = hostingQueue->GetJob(jobID);
if (useAttributesResponse == "Y")
{
TroubleSpotter::SpotTroubleUsingJobAttributes(theJob);
// TroubleSpotter class is defined in the complete example.
} else
{
TroubleSpotter::SpotTroubleUsingProperties(theJob);
}
TroubleSpotter::ReportQueueAndJobAvailability(theJob);
Para comprobar estado del trabajo de impresión mediante los marcadores de la propiedad JobStatus, se comprueba cada marcador pertinente para ver si está establecido. La manera estándar de comprobar si un bit está establecido en un conjunto de indicadores de bits, es realizar la operación de AND lógico con el conjunto de marcadores como uno de los operandos y con el propio marcador como el otro operando. Puesto que el marcador únicamente tiene un bit establecido, el resultado de la operación de AND lógico es que, a lo sumo, ese mismo bit está establecido. Para averiguar si lo está o no, basta con comparar el resultado de la operación de AND lógico con el propio marcador. Para obtener más información, consulte PrintJobStatus, Operador & (Referencia de C#) y FlagsAttribute.
Para cada atributo cuyo bit está establecido, el código informa de ello en la pantalla de la consola y, en ocasiones, sugiere una manera de responder. (El método HandlePausedJob al que se llama si el trabajo o la cola está en pausa se describe más adelante.)
// Check for possible trouble states of a print job using the flags of the JobStatus property
internal static void SpotTroubleUsingJobAttributes(PrintSystemJobInfo theJob)
{
if ((theJob.JobStatus & PrintJobStatus.Blocked) == PrintJobStatus.Blocked)
{
Console.WriteLine("The job is blocked.");
}
if (((theJob.JobStatus & PrintJobStatus.Completed) == PrintJobStatus.Completed)
||
((theJob.JobStatus & PrintJobStatus.Printed) == PrintJobStatus.Printed))
{
Console.WriteLine("The job has finished. Have user recheck all output bins and be sure the correct printer is being checked.");
}
if (((theJob.JobStatus & PrintJobStatus.Deleted) == PrintJobStatus.Deleted)
||
((theJob.JobStatus & PrintJobStatus.Deleting) == PrintJobStatus.Deleting))
{
Console.WriteLine("The user or someone with administration rights to the queue has deleted the job. It must be resubmitted.");
}
if ((theJob.JobStatus & PrintJobStatus.Error) == PrintJobStatus.Error)
{
Console.WriteLine("The job has errored.");
}
if ((theJob.JobStatus & PrintJobStatus.Offline) == PrintJobStatus.Offline)
{
Console.WriteLine("The printer is offline. Have user put it online with printer front panel.");
}
if ((theJob.JobStatus & PrintJobStatus.PaperOut) == PrintJobStatus.PaperOut)
{
Console.WriteLine("The printer is out of paper of the size required by the job. Have user add paper.");
}
if (((theJob.JobStatus & PrintJobStatus.Paused) == PrintJobStatus.Paused)
||
((theJob.HostingPrintQueue.QueueStatus & PrintQueueStatus.Paused) == PrintQueueStatus.Paused))
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}
if ((theJob.JobStatus & PrintJobStatus.Printing) == PrintJobStatus.Printing)
{
Console.WriteLine("The job is printing now.");
}
if ((theJob.JobStatus & PrintJobStatus.Spooling) == PrintJobStatus.Spooling)
{
Console.WriteLine("The job is spooling now.");
}
if ((theJob.JobStatus & PrintJobStatus.UserIntervention) == PrintJobStatus.UserIntervention)
{
Console.WriteLine("The printer needs human intervention.");
}
}//end SpotTroubleUsingJobAttributes
// Check for possible trouble states of a print job using the flags of the JobStatus property
static void SpotTroubleUsingJobAttributes (PrintSystemJobInfo^ theJob)
{
if ((theJob->JobStatus & PrintJobStatus::Blocked) == PrintJobStatus::Blocked)
{
Console::WriteLine("The job is blocked.");
}
if (((theJob->JobStatus & PrintJobStatus::Completed) == PrintJobStatus::Completed)
||
((theJob->JobStatus & PrintJobStatus::Printed) == PrintJobStatus::Printed))
{
Console::WriteLine("The job has finished. Have user recheck all output bins and be sure the correct printer is being checked.");
}
if (((theJob->JobStatus & PrintJobStatus::Deleted) == PrintJobStatus::Deleted)
||
((theJob->JobStatus & PrintJobStatus::Deleting) == PrintJobStatus::Deleting))
{
Console::WriteLine("The user or someone with administration rights to the queue has deleted the job. It must be resubmitted.");
}
if ((theJob->JobStatus & PrintJobStatus::Error) == PrintJobStatus::Error)
{
Console::WriteLine("The job has errored.");
}
if ((theJob->JobStatus & PrintJobStatus::Offline) == PrintJobStatus::Offline)
{
Console::WriteLine("The printer is offline. Have user put it online with printer front panel.");
}
if ((theJob->JobStatus & PrintJobStatus::PaperOut) == PrintJobStatus::PaperOut)
{
Console::WriteLine("The printer is out of paper of the size required by the job. Have user add paper.");
}
if (((theJob->JobStatus & PrintJobStatus::Paused) == PrintJobStatus::Paused)
||
((theJob->HostingPrintQueue->QueueStatus & PrintQueueStatus::Paused) == PrintQueueStatus::Paused))
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}
if ((theJob->JobStatus & PrintJobStatus::Printing) == PrintJobStatus::Printing)
{
Console::WriteLine("The job is printing now.");
}
if ((theJob->JobStatus & PrintJobStatus::Spooling) == PrintJobStatus::Spooling)
{
Console::WriteLine("The job is spooling now.");
}
if ((theJob->JobStatus & PrintJobStatus::UserIntervention) == PrintJobStatus::UserIntervention)
{
Console::WriteLine("The printer needs human intervention.");
}
};
Para comprobar el estado del trabajo de impresión mediante propiedades independientes, basta con leer cada propiedad y, si la propiedad es true, informar de ello en la pantalla de la consola y, si se desea, sugerir una manera de responder. (El método HandlePausedJob al que se llama si el trabajo o la cola está en pausa se describe más adelante.)
// Check for possible trouble states of a print job using its properties
internal static void SpotTroubleUsingProperties(PrintSystemJobInfo theJob)
{
if (theJob.IsBlocked)
{
Console.WriteLine("The job is blocked.");
}
if (theJob.IsCompleted || theJob.IsPrinted)
{
Console.WriteLine("The job has finished. Have user recheck all output bins and be sure the correct printer is being checked.");
}
if (theJob.IsDeleted || theJob.IsDeleting)
{
Console.WriteLine("The user or someone with administration rights to the queue has deleted the job. It must be resubmitted.");
}
if (theJob.IsInError)
{
Console.WriteLine("The job has errored.");
}
if (theJob.IsOffline)
{
Console.WriteLine("The printer is offline. Have user put it online with printer front panel.");
}
if (theJob.IsPaperOut)
{
Console.WriteLine("The printer is out of paper of the size required by the job. Have user add paper.");
}
if (theJob.IsPaused || theJob.HostingPrintQueue.IsPaused)
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}
if (theJob.IsPrinting)
{
Console.WriteLine("The job is printing now.");
}
if (theJob.IsSpooling)
{
Console.WriteLine("The job is spooling now.");
}
if (theJob.IsUserInterventionRequired)
{
Console.WriteLine("The printer needs human intervention.");
}
}//end SpotTroubleUsingProperties
// Check for possible trouble states of a print job using its properties
static void SpotTroubleUsingProperties (PrintSystemJobInfo^ theJob)
{
if (theJob->IsBlocked)
{
Console::WriteLine("The job is blocked.");
}
if (theJob->IsCompleted || theJob->IsPrinted)
{
Console::WriteLine("The job has finished. Have user recheck all output bins and be sure the correct printer is being checked.");
}
if (theJob->IsDeleted || theJob->IsDeleting)
{
Console::WriteLine("The user or someone with administration rights to the queue has deleted the job. It must be resubmitted.");
}
if (theJob->IsInError)
{
Console::WriteLine("The job has errored.");
}
if (theJob->IsOffline)
{
Console::WriteLine("The printer is offline. Have user put it online with printer front panel.");
}
if (theJob->IsPaperOut)
{
Console::WriteLine("The printer is out of paper of the size required by the job. Have user add paper.");
}
if (theJob->IsPaused || theJob->HostingPrintQueue->IsPaused)
{
HandlePausedJob(theJob);
//HandlePausedJob is defined in the complete example.
}
if (theJob->IsPrinting)
{
Console::WriteLine("The job is printing now.");
}
if (theJob->IsSpooling)
{
Console::WriteLine("The job is spooling now.");
}
if (theJob->IsUserInterventionRequired)
{
Console::WriteLine("The printer needs human intervention.");
}
};
El método HandlePausedJob permite al usuario de la aplicación reanudar remotamente los trabajos en pausa. Dado que puede existir una razón de peso por la que se ha puesto en pausa la cola de impresión, el método comienza solicitando una decisión del usuario sobre si reanudarla o no. Si la respuesta es "Y" (Sí), entonces se llama al método PrintQueue.Resume.
Luego, se pide al usuario que decida si se debe reanudar el propio trabajo, por si se ha puesto en pausa con independencia de la cola de impresión. (Observe las diferencias entre PrintQueue.IsPaused y PrintSystemJobInfo.IsPaused.) Si la respuesta es "Y" (Sí), entonces se llama al método PrintSystemJobInfo.Resume, de lo contrario, se llama al método Cancel.
internal static void HandlePausedJob(PrintSystemJobInfo theJob)
{
// If there's no good reason for the queue to be paused, resume it and
// give user choice to resume or cancel the job.
Console.WriteLine("The user or someone with administrative rights to the queue" +
"\nhas paused the job or queue." +
"\nResume the queue? (Has no effect if queue is not paused.)" +
"\nEnter \"Y\" to resume, otherwise press return: ");
String resume = Console.ReadLine();
if (resume == "Y")
{
theJob.HostingPrintQueue.Resume();
// It is possible the job is also paused. Find out how the user wants to handle that.
Console.WriteLine("Does user want to resume print job or cancel it?" +
"\nEnter \"Y\" to resume (any other key cancels the print job): ");
String userDecision = Console.ReadLine();
if (userDecision == "Y")
{
theJob.Resume();
}
else
{
theJob.Cancel();
}
}//end if the queue should be resumed
}//end HandlePausedJob
static void HandlePausedJob (PrintSystemJobInfo^ theJob)
{
// If there's no good reason for the queue to be paused, resume it and
// give user choice to resume or cancel the job.
Console::WriteLine("The user or someone with administrative rights to the queue" + "\nhas paused the job or queue." + "\nResume the queue? (Has no effect if queue is not paused.)" + "\nEnter \"Y\" to resume, otherwise press return: ");
String^ resume = Console::ReadLine();
if (resume == "Y")
{
theJob->HostingPrintQueue->Resume();
// It is possible the job is also paused. Find out how the user wants to handle that.
Console::WriteLine("Does user want to resume print job or cancel it?" + "\nEnter \"Y\" to resume (any other key cancels the print job): ");
String^ userDecision = Console::ReadLine();
if (userDecision == "Y")
{
theJob->Resume();
} else
{
theJob->Cancel();
}
}
};
Vea también
Conceptos
Documentos en Windows Presentation Foundation
Información general sobre impresión