Получение состояния принтера и задания печати
В этой статье описывается, как получить состояние принтера и задания печати с помощью средства spooler Win32.
Исходная версия продукта: Диспетчер очереди Win32
Исходный номер базы знаний: 160129
Состояние принтеров и заданий печати обновляется диспетчером очереди Win32 во время десполи задания печати. В остальных случаях, когда этот принтер не десполичен и не сообщает сведения о состоянии, принтер считается готовым и бездействующим.
Как упоминалось в API Win32, принтер состоит из драйвера принтера, очереди печати и пути ввода-вывода к физическому принтеру. Операционная система рассматривает физический принтер как просто назначение задания печати, созданного и переданного через системный принтер, который в остальной части этой статьи называется принтером.
Наиболее видимой частью принтера является очередь печати. Он управляется диспетчером печати или папками принтеров в пользовательских интерфейсах Windows 95. Драйвер принтера — это интерфейс принтера, используемый приложениями для создания заданий печати с помощью контроллеров домена принтера. Путь ввода-вывода для принтера состоит из нескольких уровней системного кода, кульминацией которого является монитор портов.
Монитор портов — это интерфейс физического принтера на нижнем конце системного принтера и отвечает за передачу данных задания печати через любое существующее подключение к физическому принтеру. В случае двунаправленных принтеров монитор портов будет отвечать за передачу данных на физический принтер и из нее. Это подключение и физический принтер являются местом возникновения ошибок. Это задача монитора портов, чтобы сообщить об этих ошибках.
Диспетчер очереди не запрашивает состояние физического принтера, к которому подключен принтер. Вместо этого состояние физического принтера определяет успешность задания печати в момент его переноса на монитор порта. Если в этом процессе возникает какая-то ошибка, она сообщается монитором порта и записывается в сведения о состоянии задания печати. Диспетчер очереди, в свою очередь, распространяет разумные сведения об ошибках в очередь принтера.
Следовательно, системный принтер не сообщает о состоянии, если очередь принтера пуста. В этом состоянии предполагается, что принтер готов к приему заданий печати. Это допустимое предположение, даже если физический принтер находится в состоянии ошибки, например в автономном режиме. Операционная система считает принтер готовым к приему заданий печати, даже если по какой-либо причине он не может завершить доставку на физический принтер. Такое обстоятельство считается состоянием ошибки в операционной системе, которую должен устранить пользователь. Это не считается ошибкой, сообщаемой приложению, которому разрешено успешно завершить выполнение задания печати.
Определение состояния физического принтера
Существует одна основная предпосылка, которая должна быть верной для определения состояния физического принтера: диспетчер очереди должен пытаться отправить задание печати на физический принтер. Это единственный раз, когда монитор портов сообщает о состоянии принтера. Кроме того, наиболее значимая информация может быть сообщена в элементах состояния структуры для этого конкретного JOB_INFO
задания печати, так как некоторые мониторы портов будут задавать эти значения напрямую.
Структуры JOB_INFO
содержат Status
элемент и pStatus
элемент . Оба элемента содержат сведения о состоянии задания печати, сообщаемые монитором портов. Эти два элемента отличаются тем, что Status
элемент — это битовое поле состояний, содержащее предопределенные значения, а pStatus
член — это указатель на строку, которая может содержать что угодно. Эти значения задокументированы пакетом SDK для Win32 и файлом заголовка WinSpool.h. Иногда pStatus
члену присваивается описательная строка состояния, но не всегда. Содержимое этой строки определяется каждым монитором портов.
JOB_INFO
структуры возвращаются двумя функциями API: GetJob
и EnumJobs
. 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_PAUSED
или JOB_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, в очереди принтеров может быть несколько заданий печати, которые будут сообщать о состоянии. Этот пример кода не учитывает это обстоятельство.