获取打印机和打印作业的状态

本文介绍如何使用 Win32 后台处理程序获取打印机和打印作业的状态。

原始产品版本:  Win32 后台处理程序
原始 KB 数:  160129

打印机和打印作业的状态在 despool 的打印作业的过程中由 Win32 后台处理程序进行更新。 在任何其他情况下,当该打印机不 despooling 且报告无状态信息时,该打印机被视为已准备就绪且处于空闲状态。

如 Win32 API 所引用的,打印机由打印机驱动程序、打印队列和物理打印机的输入/输出路径组成。 操作系统将物理打印机视为仅由生成的打印作业的目标,并通过系统打印机传递,在本文的其余部分中称为打印机。

打印机最可见的部分是打印队列。 它由 "打印管理器" 或 Windows 95 样式用户界面中的打印机文件夹进行管理。 打印机驱动程序是指应用程序用来通过打印机 Dc 创建打印作业的打印机的接口。 打印机的 i/o 路径由多个系统代码层 culminating 和一个端口监视器组成。

端口监视器是物理打印机的接口,位于系统打印机的下流端,负责将打印作业的数据传输到物理打印机存在的任何连接上。 对于双向打印机,端口监视器负责将数据传输到物理打印机和从物理打印机传输数据。 此连接和物理打印机是错误发生的地方。 它是端口监视器用于报告这些错误的作业。

后台打印程序不会查询连接打印机的物理打印机的状态。 相反,物理打印机的状态决定在 despooled 通过端口监视器进行打印作业时是否成功。 如果在此过程中出现一些错误,则端口监视器会报告错误并将其记录在打印作业的状态信息中。 后台打印程序反过来会将合理的错误信息传播到打印机队列。

因此,当打印机队列为空时,系统打印机将报告 "无" 状态。 在此状态下,将假定打印机已准备就绪,可以接受打印作业。 这是一个有效的假设,即使物理打印机处于错误状态(如脱机)也是如此。 操作系统认为打印机已准备好接受打印作业,即使由于某种原因,它无法完成与物理打印机的传递。 此类情况被视为操作系统中必须由用户解决的错误状态。 不会将其视为可报告给允许成功完成打印作业的后台打印的应用程序的错误。

确定物理打印机的状态

若要确定物理打印机的状态,必须满足一个基本的前提条件:后台打印程序必须尝试向物理打印机发送打印作业。 这是端口监视器仅报告打印机状态的唯一时间。 此外,该特定打印作业的结构的状态成员中可能会报告最有意义的信息, JOB_INFO 因为某些端口监视器将直接设置这些值。

这些 JOB_INFO 结构包含一个 Status 成员和一个 pStatus 成员。 这两个成员都包含端口监视器报告的打印作业的状态信息。 这两个成员不同之处在于, Status 成员是包含预设值的状态的位域,而 pStatus member 是指向可能包含任何内容的字符串的指针。 这些值由 Win32 SDK 和 WinSpool 头文件记录。 pStatus有时(但不总是)将成员设置为描述性状态字符串。 此字符串的内容由每个端口监视器定义。

JOB_INFO结构由两个 API 函数返回: GetJobEnumJobsEnumJobs返回一个结构数组, JOB_INFO 而不要求呼叫者引用打印机队列中的特定作业。 当前 despooling 的打印作业 (打印) 包含状态信息。 若要在数组中查找此作业,请搜索 JOB_INFO 结构数组以查找其 Status 成员具有位集的打印作业 JOB_STATUS_PRINTING

确定打印机状态的更简单方法是检查 Status 结构的成员 PRINTER_INFO 。 此结构由 GetPrinter 函数返回。 这种方法的缺点是, pStatus 结构中没有 PRINTER_INFO 可能提供更详细或更广泛的状态信息的字符串成员。 但是,端口监视器可能会设置结构的一些更广泛的打印机状态位,这样做有一个优势 PRINTER_INFO 。 但是,默认的 Windows 端口监视器不会设置超过 PRINTER_STATUS_ERROR 打印机成员的位 Status

备注

Status一组结构中的成员可能包含与物理打印机不严格相关的状态信息。 例如, Status PRINTER_INFO 可以使用或设置与 PRINTER_STATUS_PAUSED PRINTER_STATUS_PENDING_DELETION 打印队列严格相关的结构的成员。 此外, Status 结构的成员 JOB_INFO 可能包含或的状态值 JOB_STATUS_PAUSED JOB_STATUS_DELETING ,这些值仅与该特定的打印作业相关。 在打印队列中,打印作业可能会在 despooled 后累计,并将保留为的状态 JOB_STATUS_PRINTED

这些函数中的每一个都需要一个打印机句柄来标识所需的打印机。 此句柄是从 OpenPrinter 函数获取的,该函数接受包含打印机名称的字符串。 此名称可以是打印机的本地名称,也可以是网络打印机的 UNC 共享名称。

下面的示例代码演示如何 EnumJobs 正确调用函数以检索 JOB_INFO 结构以及如何调用 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 上启用打印机池时,可能会有多个打印作业 despooling 来自将报告状态的打印机队列。 此示例代码并不考虑这种情况。