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


概要


在打印作业的 despool Win32 后台打印程序更新打印机和打印作业的状态。在所有其他情况下,当该打印机不 despooling,并不报告任何状态信息,打印机被认为可以就绪并闲置。

详细信息


引用的 Win32 API,如"打印机"的打印机驱动程序、 打印队列中和组成物理打印机的输入/输出路径。操作系统将视为仅仅是打印作业生成和传递系统"打印机,"为打印机这篇文章的其余部分中引用的目标的物理打印机。


打印机的最可见部分是打印队列。它由打印管理器或 Windows 95 式用户界面中的打印机文件夹管理。打印机驱动程序是应用程序用于创建通过 DCs 打印机的打印作业的打印机的接口。打印机的 I/O 路径包含的最后完成与端口监视器的系统代码的多个图层。


端口监视器是下游一端的系统打印机的物理打印机的接口,并负责跨到物理打印机存在任何连接传输的数据的打印作业。在双向打印机端口监视器是负责传送数据和物理打印机。这种连接和物理打印机,将发生错误的位置。它是端口监视器报告这些错误的工作。


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


因此,系统打印机报告无状态时打印机队列为空。在此状态下,打印机则认为可以接受的打印作业。这是一个合理的假定,即使物理打印机处于错误状态如离线。操作系统认为可以接受的打印作业,即使出于某种原因,它不能完成交付给物理打印机的打印机。这种情况被视为必须由用户的操作系统中错误状态。不会认为该错误报告给应用程序成功完成后台处理的打印作业,允许。

确定物理打印机的状态

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


JOB_INFO结构包含状态成员和pStatus成员。这两个成员包含端口监视器报告的打印作业的状态信息。这两个成员不同,状态成员是包含预设的值,而该pStatus成员是指向字符串可能包含的任何 bit 字段的状态。这些值是由 Win32 SDK 和 WinSpool.h 头文件记录。PStatus成员有时,但不是总是设置为一个字符串,描述状态。此字符串的内容定义的每个端口监视器。


JOB_INFO结构由两个 API 函数: GetJob 和 EnumJobs。EnumJobs 返回的数组JOB_INFO结构不要求调用方引用特定作业在打印队列中。目前 despooling (打印) 打印作业包含状态信息。搜索查找打印作业的状态成员具有 JOB_STATUS_PRINTING 的JOB_INFO结构的数组,数组中查找此作业设置的位。


确定打印机状态的更简单的方法是检查状态PRINTER_INFO结构的成员。GetPrinter函数返回此结构。可能会提供更详尽的详细的状态信息的PRINTER_INFO结构中都没有pStatus字符串成员没有对这种方法的一个缺点。但是,没有优势,因为端口监视器可能会设置一些更广泛的打印机PRINTER_INFO结构的状态位。但是请注意,Windows 默认端口监视器不会通常不设置多个打印机的状态成员的PRINTER_STATUS_ERROR位。


请注意,这两组结构的状态成员可能包含与物理打印机不严格相关的状态信息。例如, PRINTER_INFO结构的状态成员可能设置与PRINTER_STATUS_PAUSEDPRINTER_STATUS_PENDING_DELETION,严格相关的打印队列。此外,状态JOB_INFO结构的成员可能包含JOB_STATUS_PAUSEDJOB_STATUS_DELETING,仅对该特定打印作业相关的状态的值。另外,请注意,打印作业可能会在打印队列中累积之后他们已经交给并将保持与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 并将报告状态。此示例代码不会考虑该情况。

参考资料


调用 Win32 后台处理程序函数的一般说明的其他信息,请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:

158828如何对调用 Wind32 后台程序枚举 Api 正确