Condividi tramite


Procedura: diagnosticare processi di stampa problematici

Aggiornamento: novembre 2007

Gli amministratori di rete spesso devono far fronte ai reclami degli utenti relativamente a processi di stampa non eseguiti oppure lenti. La vasta gamma di proprietà dei processi di stampa esposta nelle API di Microsoft .NET Framework consente la rapida diagnosi remota di questi processi.

Esempio

Di seguito vengono descritti i passaggi principali per la creazione di questo tipo di utilità:

  1. Identificare il processo di stampa oggetto del reclamo dell'utente. Spesso, infatti, gli utenti non sono in grado di individuarlo con precisione, in quanto è probabile che non conoscano i nomi dei server di stampa o delle stampanti e indichino il percorso della stampante con una terminologia diversa da quella utilizzata nell'impostazione della proprietà Location. Di conseguenza, è opportuno generare un elenco dei processi inviati dall'utente in quel momento. Nel caso in cui si tratti di più processi, è possibile utilizzare la comunicazione tra l'utente e l'amministratore del sistema di stampa per individuare il processo problematico. La procedura è indicata di seguito.

    1. Ottenere un elenco di tutti i server di stampa.

    2. Scorrere i server per eseguire una query sulle relative code di stampa.

    3. In ogni passaggio del ciclo di server, scorrere tutte le code del server per eseguire una query sui relativi processi.

    4. In ogni passaggio del ciclo di code, scorrere i processi e raccogliere le informazioni di identificazione relative ai processi inviati dall'utente che ha eseguito il reclamo.

  2. Una volta identificato il processo di stampa problematico, esaminare le proprietà rilevanti per individuare l'eventuale problema. Verificare, ad esempio, se il processo si trova in uno stato di errore oppure se la stampante che gestisce la coda è passata alla modalità non in linea prima della stampa.

Il codice riportato di seguito è costituito da una serie di esempi di codice. Per l'esempio completo, vedere Esempio di diagnosi di processi di stampa problematici.

Il primo esempio di codice contiene il ciclo per scorrere le code di stampa (vedere il passaggio 1c precedente). La variabile myPrintQueues è l'oggetto PrintQueueCollection per il server di stampa corrente.

L'esempio di codice ha inizio con l'aggiornamento dell'oggetto coda di stampa corrente con PrintQueue.Refresh. In tal modo si garantisce che le proprietà dell'oggetto rappresentino con precisione lo stato della stampante fisica. L'applicazione ottiene quindi l'insieme dei processi di stampa attualmente presenti nella coda di stampa utilizzando GetPrintJobInfoCollection.

Successivamente l'applicazione scorre l'insieme PrintSystemJobInfo e confronta ciascuna proprietà Submitter con l'alias dell'utente che ha eseguito il reclamo. Se questi corrispondono, alla stringa visualizzata verranno aggiunte delle informazioni di identificazione relative al processo. Le variabili userName e jobList vengono inizializzate precedentemente all'interno applicazione.

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

Nel successivo esempio di codice l'applicazione viene illustrata a partire dal passaggio 2 (vedere sopra). Il processo problematico è stato individuato e l'applicazione richiede le informazioni che consentono di identificarlo. Tali informazioni vengono utilizzate per creare gli oggetti PrintServer, PrintQueue e PrintSystemJobInfo.

A questo punto l'applicazione conterrà una struttura con diramazioni, corrispondente alle due modalità di verifica dello stato di un processo di stampa:

Nell'esempio vengono illustrati entrambi i metodi. All'utente è stato pertanto richiesto di scegliere il metodo da utilizzare e di rispondere con "Y" per utilizzare i flag della proprietà JobStatus. Per informazioni dettagliate relative ai due metodi vedere di seguito. Infine, l'applicazione utilizza un metodo denominato ReportQueueAndJobAvailability per segnalare se è possibile eseguire il processo di stampa in quel preciso momento. Il metodo viene illustrato in Procedura: individuare se è possibile eseguire o meno un processo di stampa all'orario indicato.

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

Per controllare lo stato del processo di stampa utilizzando i flag della proprietà JobStatus, esaminare ogni flag pertinente per verificare se è impostato. La modalità standard per verificare se in un set di flag di bit è stato impostato un determinato bit consiste nell'eseguire un'operazione di AND logico in cui un operando sia costituito dal set di flag e l'altro dal flag stesso. Dal momento che il flag stesso dispone di un solo bit impostato, il risultato dell'operazione di AND logico consisterà, al più, nell'impostazione dello stesso bit. Per verificare se il bit è impostato, confrontare il risultato dell'operazione di AND logico con il flag stesso. Per ulteriori informazioni, vedere PrintJobStatus, Operatore & (Riferimenti per C#) e FlagsAttribute.

Per ciascun attributo in cui il bit è impostato, il codice invia una segnalazione allo schermo della console, talvolta insieme a un suggerimento relativo alla modalità di risposta. Il metodo HandlePausedJob, chiamato se il processo o la coda è in pausa, è illustrato di seguito.

// 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.");
   }
};

Per controllare lo stato del processo di stampa utilizzando proprietà separate, leggere ciascuna proprietà e, se il relativo valore è true, inviare una segnalazione allo schermo della console insieme a un eventuale suggerimento relativo alla modalità di risposta. Il metodo HandlePausedJob, chiamato se il processo o la coda è in pausa, è illustrato di seguito.

// 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.");
   }
};

Il metodo HandlePausedJob consente all'utente dell'applicazione di riprendere i processi in pausa da postazione remota. Dal momento che la sospensione della coda di stampa potrebbe essere causata da un motivo valido, all'utente viene chiesto innanzitutto di decidere se riprenderla. Se la risposta è "Y", viene chiamato il metodo PrintQueue.Resume.

Successivamente all'utente viene richiesto di decidere se riprendere il processo stesso, nel caso quest'ultimo fosse in pausa indipendentemente dalla coda di stampa. Confrontare PrintQueue.IsPaused e PrintSystemJobInfo.IsPaused. Se la risposta è "Y", viene chiamato PrintSystemJobInfo.Resume; in caso contrario, viene chiamato 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();
      }
   }
};

Vedere anche

Concetti

Documenti di Windows Presentation Foundation

Cenni preliminari sulla stampa

Riferimenti

PrintJobStatus

PrintSystemJobInfo

Operatore & (Riferimenti per C#)

FlagsAttribute

PrintQueue

Altre risorse

Esempi relativi alla stampa