取得印表機和列印作業的狀態
本文介紹如何使用 Win32 多任務緩衝處理器取得印表機和列印作業的狀態。
原始產品版本: Win32 多任務緩衝處理器
原始 KB 編號: 160129
在列印作業的 despool 期間,Win32 多任務緩衝處理器會更新印表機和列印作業的狀態。 在所有其他時間,當該印表機未還原後置,且未報告狀態資訊時,列印機會被視為就緒且閑置。
如 Win32 API 所述,印表機是由印表機驅動程式、列印佇列,以及實體列印機的輸入/輸出路徑所組成。 操作系統會將實體印表機視為所產生且通過系統印表機之列印作業的目的地,本文其餘部分稱為「印表機」。
印表機最明顯的部分是列印佇列。 它是由 Windows 95 樣式使用者介面中的列印管理員或印表機資料夾所管理。 印表機驅動程式是印表機的介面,應用程式會使用此介面透過印表機DC建立列印作業。 印表機的 I/O 路徑是由數層系統程式代碼組成,其中包含埠監視器。
埠監視器是位於系統印表機下流端的實體列印機介面,負責將印表作業的數據傳輸到實體印表機的任何連線。 如果是雙向印表機,埠監視器會負責將數據傳輸到實體印表機,以及從實體列印機傳送數據。 此連線和實體印表機是發生錯誤的位置。 埠監視器的工作是報告這些錯誤。
多任務緩衝處理程式不會查詢印表機所連接之實體印表機的狀態。 相反地,實體印表機的狀態會決定在透過埠監視器還原後,列印作業是否成功。 如果在此程式中發生一些錯誤,則埠監視器會報告錯誤,並記錄在列印作業的狀態資訊中。 接著,多任務緩衝處理器會將合理的錯誤資訊傳播到印表機佇列。
因此,當印表機佇列是空的時,系統列印機不會報告任何狀態。 在此狀態下,會假設印表機已準備好接受列印作業。 即使實體印表機處於離線之類的錯誤狀態,這也是有效的假設。 操作系統會將印表機視為可接受印表作業,即使因為某些原因而無法完成傳遞至實體印表機。 這類情況會被視為操作系統中必須由使用者解決的錯誤狀態。 對於允許順利完成列印作業多任務緩衝處理的應用程式,並不會將其視為可回報的錯誤。
判斷實體印表機的狀態
有一個基本的前提必須為 true,才能判斷實體印表機的狀態:多任務緩衝處理器必須嘗試將列印作業傳送至實體列印機。 這是埠監視器唯一報告印表機狀態的時間。 此外,在該特定列印作業的 JOB_INFO
結構狀態成員中,可能會報告最有意義的信息,因為某些埠監視器會直接設定這些值。
結構 JOB_INFO
包含 Status
成員和 pStatus
成員。 這兩個成員都包含埠監視器所報告之列印作業的狀態資訊。 這兩個成員的不同之處在於, Status
成員是包含預先決定值的狀態位字段,而 pStatus
成員是字串的指標,可包含幾乎任何專案。 這些值會由 Win32 SDK 和 WinSpool.h 頭文件記載。 成員 pStatus
有時會設定為描述性狀態字串,但不一定會設定為描述性狀態字串。 此字串的內容是由每個埠監視器所定義。
JOB_INFO
結構是由兩個 API 函式傳回:和 EnumJobs
。 GetJob
EnumJobs
傳回 結構的 JOB_INFO
陣列,而不需要呼叫端參考印表機佇列中的特定作業。 列印) 目前還原緩衝處理 (列印作業包含狀態資訊。 若要在陣列中尋找此作業,請搜尋 結構的 JOB_INFO
陣列印作業, 以找出其 Status
成員具有位集的 JOB_STATUS_PRINTING
列印作業。
判斷印表機狀態的較簡單方法是檢查 Status
結構的成員 PRINTER_INFO
。 函式會傳回這個 GetPrinter
結構。 這種方法有一個缺點,就是結構中PRINTER_INFO
沒有pStatus
字串成員可以提供更詳細或廣泛的狀態資訊。 不過,埠監視器可能會設定結構的一些更廣泛印表機狀態位 PRINTER_INFO
,有一個優點。 不過,Windows 的預設埠監視器未設定超過 PRINTER_STATUS_ERROR
印表機成員的 Status
位。
注意事項
任 Status
一組結構的成員可能包含與實體印表機不完全相關的狀態資訊。 例如, Status
結構的成員 PRINTER_INFO
可以使用 PRINTER_STATUS_PAUSED
或 PRINTER_STATUS_PENDING_DELETION
來設定,這完全與列印佇列相關。 此外,Status
結構的成員JOB_INFO
可能包含 或JOB_STATUS_DELETING
的JOB_STATUS_PAUSED
狀態值,而這些值只與該特定列印作業相關。 將列印作業還原後,列印作業可能會累積在列印佇列中,並保留狀態為 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 上啟用印表機共用時,可能會有一個以上的列印作業從印表機佇列還原多任務緩衝處理,以報告狀態。 此範例程式代碼不會考慮這種情況。