プリンターと印刷ジョブの状態を取得する

この記事では、Win32 スプーラーを使用してプリンターと印刷ジョブの状態を取得する方法について説明します。

元の製品バージョン: Win32 スプーラー
元の KB 番号: 160129

プリンターと印刷ジョブの状態は、印刷ジョブのデスプール中に Win32 スプーラーによって更新されます。 それ以外の場合でも、そのプリンターがデスプールされておらず、状態情報が報告されない場合、プリンターは準備が整い、アイドル状態であると見なされます。

Win32 API で参照されるように、プリンターはプリンター ドライバー、印刷キュー、および物理プリンターへの入出力パスで構成されます。 オペレーティング システムは、物理プリンターを、この記事の残りの部分でプリンターと呼ばれるシステム プリンターによって生成され、渡される印刷ジョブの宛先として扱います。

プリンターの最も目に見える部分は、印刷キューです。 これは、Windows 95 スタイルのユーザー インターフェイスの印刷マネージャーまたはプリンター フォルダーによって管理されます。 プリンター ドライバーは、プリンター DC を使用して印刷ジョブを作成するためにアプリケーションによって使用されるプリンターへのインターフェイスです。 プリンターの I/O パスは、ポート モニターで最高のシステム コードの複数のレイヤーで構成されます。

ポート・モニターは、システム・プリンターのダウン・ストリーム・エンドにある物理プリンターへのインターフェースであり、物理プリンターに存在する接続を介して印刷ジョブのデータを転送する役割を担います。 双方向プリンターの場合、ポート モニターは、物理プリンターとの間でデータを転送する役割を担います。 この接続と物理プリンターは、エラーが発生する場所です。 これらのエラーを報告するのは、ポート モニターのジョブです。

スプーラーは、プリンターが接続されている物理プリンターの状態を照会しません。 代わりに、物理プリンターの状態によって、ポート モニター経由で印刷ジョブがデスプールされた時点での印刷ジョブの成功が決まります。 このプロセスで何らかのエラーが発生した場合、エラーはポート・モニターによって報告され、印刷ジョブの状況情報に記録されます。 スプーラーは、適切なエラー情報をプリンター キューに伝達します。

そのため、プリンター キューが空の場合、システム プリンターは状態を報告しません。 この状態では、プリンターは印刷ジョブを受け入れる準備ができていると見なされます。 これは、物理プリンターがオフラインなどのエラー状態にある場合でも、有効な想定です。 オペレーティング システムは、何らかの理由で物理プリンターへの配信を完了できない場合でも、プリンターが印刷ジョブを受け入れる準備ができていると見なします。 このような状況は、ユーザーが対処する必要があるオペレーティング システムのエラー状態と見なされます。 印刷ジョブのスプールを正常に完了できるアプリケーションに報告可能なエラーとは見なされません。

物理プリンターの状態を判別する

物理プリンターの状態を判断するには、1 つの基本的な前提として true を指定する必要があります。スプーラーは、印刷ジョブを物理プリンターに送信しようとしている必要があります。 これは、プリンターの状態がポート モニターによって報告される唯一の時間です。 さらに、一部のポート モニターでこれらの値が直接設定されるため、その特定の印刷ジョブの構造体の JOB_INFO 状態メンバーで最も意味のある情報が報告される場合があります。

構造体にはJOB_INFO、メンバーとメンバーがpStatusStatusまれています。 両方のメンバーには、ポート・モニターによって報告された印刷ジョブの状況情報が含まれます。 これら 2 つのメンバーは、メンバーが事前に定義された値を含む状態のビット フィールドであるという点で異なります Status が、 pStatus メンバーは何でも含めることができる文字列へのポインターです。 これらの値は、Win32 SDK と WinSpool.h ヘッダー ファイルによって文書化されています。 メンバーは pStatus 、説明的な状態文字列に設定されている場合がありますが、常に設定されるわけではありません。 この文字列の内容は、各ポート モニターによって定義されます。

JOB_INFO構造体は、 と EnumJobsの 2 つの API 関数GetJobによって返されます。 EnumJobs は、呼び出し元がプリンター キュー内の特定の JOB_INFO ジョブを参照する必要なく、構造体の配列を返します。 現在デスプール (印刷) されている印刷ジョブには、状態情報が含まれています。 配列内でこのジョブを見つけるには、構造体の JOB_INFO 配列を検索して、メンバーにビットが設定されている Status 印刷ジョブを JOB_STATUS_PRINTING 見つけます。

プリンターの状態を判断する簡単な方法は、構造体のメンバーをStatusPRINTER_INFO調べることです。 この構造体は、 関数によって GetPrinter 返されます。 この方法には、より詳細または広範な状態情報をPRINTER_INFO提供する可能性がある構造体に文字列メンバーが存在しないpStatusという点で欠点があります。 ただし、ポート モニターは、構造体のより広範なプリンターの状態ビットの一部を PRINTER_INFO 設定する可能性があるという利点があります。 ただし、Windows の既定のポート モニターでは、プリンターStatusのメンバーのビットを超えるPRINTER_STATUS_ERROR設定は行われません。

注:

いずれかの構造体のセットのメンバーには Status 、物理的なプリンターに厳密に関連しない状態情報が含まれている場合があります。 たとえば、構造体のStatusPRINTER_INFOメンバーは、印刷キューに厳密に関連する または PRINTER_STATUS_PENDING_DELETIONを使用PRINTER_STATUS_PAUSEDして設定できます。 また、構造体のStatusメンバーには、その特定のJOB_INFO印刷ジョブにのみ関連する または JOB_STATUS_DELETINGの状態値JOB_STATUS_PAUSEDが含まれている場合があります。 印刷ジョブは、印刷キューがプールされなくなった後に累積され、 の JOB_STATUS_PRINTED状態のままになる可能性があります。

これらの各機能には、目的のプリンターを識別するためのプリンターへのハンドルが必要です。 このハンドルは、プリンターの名前を OpenPrinter 含む文字列を受け取る 関数から取得されます。 この名前には、プリンターのローカル名、またはネットワーク プリンターの UNC 共有名を指定できます。

次のサンプル コードは、構造体を取得JOB_INFOするために関数をEnumJobs適切に呼び出す方法と、関数を呼び出して構造体をGetPrinter取得PRINTER_INFOする方法を示しています。

サンプル コード

BOOL GetJobs(HANDLE hPrinter,        /* Handle to the printer. */

JOB_INFO_2 **ppJobInfo, /* Pointer to be filled.  */
                int *pcJobs,            /* Count of jobs filled.  */
                DWORD *pStatus)         /* Print Queue status.    */

{

DWORD               cByteNeeded,
                        nReturned,
                        cByteUsed;
    JOB_INFO_2          *pJobStorage = NULL;
    PRINTER_INFO_2       *pPrinterInfo = NULL;

/* Get the buffer size needed. */
       if (!GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded))
       {
           if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
               return FALSE;
       }

pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded);
       if (!(pPrinterInfo))
           /* Failure to allocate memory. */
           return FALSE;

/* Get the printer information. */
       if (!GetPrinter(hPrinter,
               2,
               (LPSTR)pPrinterInfo,
               cByteNeeded,
               &cByteUsed))
       {
           /* Failure to access the printer. */
           free(pPrinterInfo);
           pPrinterInfo = NULL;
           return FALSE;
       }

/* Get job storage space. */
       if (!EnumJobs(hPrinter,
               0,
               pPrinterInfo->cJobs,
               2,
               NULL,
               0,
               (LPDWORD)&cByteNeeded,
               (LPDWORD)&nReturned))
       {
           if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
           {
               free(pPrinterInfo);
               pPrinterInfo = NULL;
               return FALSE;
           }
       }

pJobStorage = (JOB_INFO_2 *)malloc(cByteNeeded);
       if (!pJobStorage)
       {
           /* Failure to allocate Job storage space. */
           free(pPrinterInfo);
           pPrinterInfo = NULL;
           return FALSE;
       }

ZeroMemory(pJobStorage, cByteNeeded);

/* Get the list of jobs. */
       if (!EnumJobs(hPrinter,
               0,
               pPrinterInfo->cJobs,
               2,
               (LPBYTE)pJobStorage,
               cByteNeeded,
               (LPDWORD)&cByteUsed,
               (LPDWORD)&nReturned))
       {
           free(pPrinterInfo);
           free(pJobStorage);
           pJobStorage = NULL;
           pPrinterInfo = NULL;
           return FALSE;
       }

/*
        *  Return the information.
        */
       *pcJobs = nReturned;
       *pStatus = pPrinterInfo->Status;
       *ppJobInfo = pJobStorage;
       free(pPrinterInfo);

return TRUE;

}

BOOL IsPrinterError(HANDLE hPrinter)
   {

JOB_INFO_2  *pJobs;
       int         cJobs,
                   i;
       DWORD       dwPrinterStatus;

/*
        *  Get the state information for the Printer Queue and
        *  the jobs in the Printer Queue.
        */
       if (!GetJobs(hPrinter, &pJobs, &cJobs, &dwPrinterStatus))
return FALSE;

/*
        *  If the Printer reports an error, believe it.
        */
       if (dwPrinterStatus &
           (PRINTER_STATUS_ERROR |
           PRINTER_STATUS_PAPER_JAM |
           PRINTER_STATUS_PAPER_OUT |
           PRINTER_STATUS_PAPER_PROBLEM |
           PRINTER_STATUS_OUTPUT_BIN_FULL |
           PRINTER_STATUS_NOT_AVAILABLE |
           PRINTER_STATUS_NO_TONER |
           PRINTER_STATUS_OUT_OF_MEMORY |
           PRINTER_STATUS_OFFLINE |
           PRINTER_STATUS_DOOR_OPEN))
       {
           free( pJobs );
           return TRUE;
       }

/*
        *  Find the Job in the Queue that is printing.
        */
       for (i=0; i < cJobs; i++)
       {
           if (pJobs[i].Status & JOB_STATUS_PRINTING)
           {
               /*
                *  If the job is in an error state,
                *  report an error for the printer.
                *  Code could be inserted here to
                *  attempt an interpretation of the
                *  pStatus member as well.
                */
               if (pJobs[i].Status &
                   (JOB_STATUS_ERROR |
                   JOB_STATUS_OFFLINE |
                   JOB_STATUS_PAPEROUT |
                   JOB_STATUS_BLOCKED_DEVQ))
               {
                   free( pJobs );
                   return TRUE;
               }
           }
       }

/*
        *  No error condition.
        */
       free( pJobs );
       return FALSE;

}

注:

Windows NTでプリンター プールが有効になっている場合、状態を報告するプリンター キューから複数の印刷ジョブがデスプールされている可能性があります。 このサンプル コードでは、その状況は考慮されません。