다음을 통해 공유


방법: 인쇄 작업 문제 진단

업데이트: 2007년 11월

인쇄되지 않거나 느리게 인쇄되는 인쇄 작업과 관련된 사용자의 불만을 네트워크 관리자가 해결하는 경우가 흔히 있습니다. Microsoft .NET Framework의 API에 노출된 다양한 인쇄 작업 속성 집합은 인쇄 작업을 원격에서 빠르게 진단할 수 있는 방법을 제공합니다.

예제

이러한 종류의 유틸리티를 만드는 주요 단계는 다음과 같습니다.

  1. 사용자가 불만족을 표시하는 인쇄 작업을 식별합니다. 사용자는 이 작업을 정확하게 수행할 수 없는 경우가 많습니다. 사용자는 인쇄 서버나 프린터의 이름을 모를 수 있습니다. 또한 해당 Location 속성을 설정할 때 사용한 것과 다른 용어로 프린터 위치를 설명할 수 있습니다. 따라서 사용자가 현재 제출한 작업의 목록을 생성하는 것이 좋습니다. 둘 이상의 작업이 있는 경우 사용자와 인쇄 시스템 관리자 간의 통신으로 문제가 있는 작업을 찾을 수 있습니다. 하위 단계는 다음과 같습니다.

    1. 모든 인쇄 서버의 목록을 가져옵니다.

    2. 서버를 순환 검색하여 해당 인쇄 큐를 쿼리합니다.

    3. 서버 루프의 각 처리 내에서 모든 서버 큐를 순환하며 해당 작업을 쿼리합니다

    4. 큐 루프의 각 처리 내에서 해당 작업을 순환하며 불평하는 사용자가 제출한 작업에 대한 식별 정보를 수집합니다.

  2. 문제가 있는 인쇄 작업을 식별했으면 관련 속성을 검사하여 문제를 확인합니다. 예를 들어 작업이 오류 상태이거나 작업이 인쇄되기 전에 큐를 처리하는 프린터가 오프라인으로 전환되었는지 확인합니다.

아래의 코드는 일련의 코드 예제입니다. 전체 샘플을 보려면 인쇄 작업 문제 진단 샘플을 참조하십시오.

첫 번째 코드 예제에는 인쇄 큐 순환이 포함되어 있습니다(위의 단계 1c 참조). myPrintQueues 변수는 현재 인쇄 서버의 PrintQueueCollection 개체입니다.

이 코드 예제에서는 먼저 PrintQueue.Refresh를 사용하여 현재 인쇄 큐를 새로 고칩니다. 그러면 개체의 속성이 해당하는 실제 프린터의 상태가 정확하게 나타나게 됩니다. 그런 다음 응용 프로그램에서는 GetPrintJobInfoCollection을 사용하여 현재 인쇄 큐에 있는 인쇄 작업을 컬렉션을 가져옵니다.

다음으로 응용 프로그램에서는 PrintSystemJobInfo 컬렉션을 순환하며 각 Submitter 속성과 불평하는 사용자의 별칭을 비교합니다. 이 둘이 일치하면 응용 프로그램에서는 작업에 대한 식별 정보를 표시할 문자열에 추가합니다. userName 및 jobList 변수는 응용 프로그램에서 이전에 초기화했습니다.

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

다음 코드 예제에서는 2단계의 응용 프로그램을 선택합니다(앞 부분 참조). 문제 있는 작업을 식별하고 나면 응용 프로그램에 문제를 식별할 정보를 입력하라는 메시지가 표시됩니다. 이 정보를 사용하여 PrintServer, PrintQueuePrintSystemJobInfo 개체를 만듭니다.

이제 응용 프로그램에는 인쇄 작업의 상태를 확인하는 두 가지 방법에 해당하는 분기 구조가 있습니다.

이 예제에서는 두 메서드를 모두 보여 줍니다. 따라서 사용자는 이전에 사용할 메서드를 묻는 메시지가 표시될 때 JobStatus 속성의 플래그를 사용하려는 경우 "Y"로 대답했을 것입니다. 두 메서드에 대한 자세한 내용은 아래를 참조하십시오. 마지막으로 응용 프로그램에서는 ReportQueueAndJobAvailability라는 메서드를 사용하여 작업을 현재 인쇄할 수 있는지 여부를 보고합니다. 이 메서드에 대해서는 방법: 인쇄 작업을 현재 인쇄할 수 있는지 확인에서 설명합니다.

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

JobStatus 속성의 플래그를 사용하여 인쇄 작업 상태를 검사하려면 관련된 각 플래그를 검사하여 설정되어 있는지 확인합니다. 한 비트가 비트 플래그 집합에 설정되어 있는지 알아볼 수 있는 표준 방법은 플래그 집합을 한 피연산자로 사용하고 플래그 자체를 다른 피연산자로 사용하여 논리 AND 연산을 수행하는 것입니다. 플래그 자체는 한 비트만 설정되므로 논리 AND의 결과는 기껏해야 같은 비트를 설정하는 것입니다. 해당 비트가 설정되어 있는지 확인하려면 논리 AND의 결과를 플래그 자체와 비교하면 됩니다. 자세한 내용은 PrintJobStatus, & 연산자(C# 참조)FlagsAttribute를 참조하십시오.

비트가 설정된 각 특성에 대해 코드에서는 이를 콘솔 화면에 보고하고 경우에 따라 응답 방법을 제안합니다. 작업 또는 큐가 일시 중지하는 경우 호출하는 HandlePausedJob 메서드에 대해서는 아래에서 설명합니다.

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

별도의 속성을 사용하여 인쇄 작업 상태를 검사하려면 각 속성을 읽고 속성이 true인 경우 콘솔 화면에 보고하고 가능한 경우 응답 방법을 제안하면 됩니다. 작업 또는 큐가 일시 중지하는 경우 호출하는 HandlePausedJob 메서드에 대해서는 아래에서 설명합니다.

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

HandlePausedJob 메서드를 사용하면 응용 프로그램의 사용자가 일시 중지된 작업을 원격으로 다시 시작할 수 있습니다. 인쇄 큐가 일시 중지된 이유가 있을 것이므로 메서드에서는 먼저 작업을 다시 시작할지 여부에 대한 사용자의 결정을 묻는 메시지를 표시합니다. "Y"로 대답하면 PrintQueue.Resume 메서드를 호출합니다.

그런 다음, 작업이 인쇄 큐와 별개로 일시 중지된 경우에 한해 작업 자체를 다시 시작할지 여부를 결정하라는 메시지를 표시합니다. PrintQueue.IsPausedPrintSystemJobInfo.IsPaused를 비교해 보십시오. "Y"로 대답하면 PrintSystemJobInfo.Resume 메서드를 호출하고 그렇지 않으면 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();
      }
   }
};

참고 항목

개념

Windows Presentation Foundation의 문서

인쇄 개요

참조

PrintJobStatus

PrintSystemJobInfo

& 연산자(C# 참조)

FlagsAttribute

PrintQueue

기타 리소스

인쇄 샘플