次の方法で共有


方法 : 問題のある印刷ジョブを診断する

更新 : 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. のアプリケーションを取り上げます (前の説明を参照)。問題のあるジョブが特定され、その識別情報の入力を求めるメッセージがアプリケーションから表示されます。この情報から、PrintServerPrintQueue、および PrintSystemJobInfo の各オブジェクトが作成されます。

この時点で、アプリケーションには次の印刷ジョブのステータスを確認する 2 つの方法に対応する分岐構造があります。

この例では両方の方法を示すため、ユーザーは使用する方法に関して入力を求められ、JobStatus プロパティのフラグを使用する場合は「Y」と応答しています。2 つの方法の詳細については、以下を参照してください。最後に、アプリケーションは 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 プロパティのフラグを使用して印刷ジョブのステータスを確認するには、各関連フラグが設定されているかどうかを確認します。1 ビットがビット フラグ セットで設定されているかどうかを確認するには、通常、フラグ セットを 1 つのオペランドとし、フラグ自体をもう 1 つのオペランドとして、論理 AND 演算を行います。フラグ自体には 1 ビットのみが設定されているため、論理 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

その他の技術情報

印刷のサンプル