Obter o status de uma impressora e um trabalho de impressão

Este artigo apresenta como obter o status de uma impressora e um trabalho de impressão usando o Spooler Win32.

Versão original do produto: Win32 Spooler
Número de KB original: 160129

O status de impressoras e trabalhos de impressão são atualizados pelo Win32 Spooler durante o despool de um trabalho de impressão. Em todos os outros momentos, quando essa impressora não está sendo desativada e não relata nenhuma informação de estado, a impressora é considerada pronta e ociosa.

Conforme referido pela API Win32, uma impressora é composta pelo driver da impressora, pela fila de impressão e pelo caminho de entrada/saída para a impressora física. O sistema operacional trata uma impressora física como apenas o destino de um trabalho de impressão gerado e passado por uma impressora do sistema, conhecida no restante deste artigo como impressora.

A parte mais visível de uma Impressora é uma fila de impressão. Ele é gerenciado pelo Gerenciador de Impressão ou pelas pastas Impressora nas interfaces de usuário estilo Windows 95. O driver da impressora é a interface da Impressora usada por aplicativos para criar trabalhos de impressão por meio de DCs de impressora. O caminho de E/S para uma Impressora consiste em várias camadas de código do sistema culminando com um monitor de porta.

O monitor de porta é a interface para a impressora física na extremidade down-stream de uma impressora do sistema e é responsável por transferir os dados de um trabalho de impressão em qualquer conexão existente para a impressora física. No caso de impressoras bidirecionais, o monitor de porta seria responsável pela transferência de dados de e para a impressora física. Essa conexão e a impressora física são onde ocorrem erros. É trabalho do monitor de porta relatar esses erros.

O Spooler não consulta o estado de uma impressora física à qual uma Impressora está conectada. Em vez disso, o estado de uma impressora física determina o sucesso de um trabalho de impressão no momento em que ele é desamarmado pelo monitor de porta. Se ocorrer algum erro nesse processo, o erro será relatado pelo monitor de porta e registrado nas informações de status de um trabalho de impressão. O Spooler, por sua vez, propaga informações de erro razoáveis para a Fila da Impressora.

Consequentemente, uma impressora do sistema não relata status quando a fila da impressora está vazia. Nesse estado, a Impressora é assumida pronta para aceitar trabalhos de impressão. Essa é uma suposição válida, mesmo que a impressora física esteja em um estado de erro, como off-line. O sistema operacional considera a Impressora pronta para aceitar trabalhos de impressão mesmo que, por algum motivo, não possa concluir a entrega à impressora física. Essa circunstância é considerada um estado de erro no sistema operacional que deve ser resolvido pelo usuário. Ele não é considerado um erro reportável ao aplicativo que pode concluir o spooling do trabalho de impressão com êxito.

Determinar o estado de uma impressora física

Há uma premissa fundamental que deve ser verdadeira para determinar o estado de uma impressora física: o Spooler deve estar tentando enviar um trabalho de impressão para a impressora física. Essa é a única vez que o estado da impressora é relatado pelo monitor de porta. Além disso, as informações mais significativas podem ser relatadas no status membros de uma JOB_INFO estrutura para esse trabalho de impressão específico, pois algum monitor de porta terá definido esses valores diretamente.

As JOB_INFO estruturas contêm um Status membro e um pStatus membro. Ambos os membros contêm status informações de um trabalho de impressão relatado pelo monitor de porta. Esses dois membros diferem porque o Status membro é um campo bit de estados que contém valores predeterminados, enquanto o pStatus membro é um ponteiro para uma cadeia de caracteres que pode conter praticamente qualquer coisa. Esses valores são documentados pelo SDK do Win32 e pelo arquivo de cabeçalho WinSpool.h. Às vezes, o pStatus membro é, mas nem sempre, definido como uma cadeia de caracteres de status descritiva. O conteúdo dessa cadeia de caracteres é definido por cada monitor de porta.

JOB_INFO as estruturas são retornadas por duas funções de API: GetJob e EnumJobs. EnumJobs retorna uma matriz de JOB_INFO estruturas sem exigir que o chamador faça referência a um trabalho específico na fila impressora. O trabalho de impressão que está sendo desativado no momento (impressão) contém as informações status. Para encontrar esse trabalho na matriz, pesquise a matriz de JOB_INFO estruturas para localizar o trabalho de impressão cujo Status membro tenha o JOB_STATUS_PRINTING conjunto de bits.

Um método mais fácil de determinar a impressora status é examinar o Status membro de uma PRINTER_INFO estrutura. Essa estrutura é retornada pela GetPrinter função. Há uma desvantagem nessa abordagem em que não há nenhum pStatus membro de cadeia de caracteres em uma PRINTER_INFO estrutura que possa fornecer informações de estado mais detalhadas ou extensas. No entanto, há uma vantagem em que um monitor de porta pode definir alguns dos bits de status de impressora mais extensos da PRINTER_INFO estrutura. No entanto, que o monitor de porta padrão para Windows não define mais do que o PRINTER_STATUS_ERROR bit de um membro da Status Impressora.

Observação

Os Status membros de qualquer conjunto de estruturas podem conter informações de estado que não estão estritamente relacionadas à impressora física. Por exemplo, o Status membro das PRINTER_INFO estruturas pode ser definido com PRINTER_STATUS_PAUSED ou PRINTER_STATUS_PENDING_DELETION, que são estritamente relevantes para a Fila de Impressão. Além disso, o Status membro da JOB_INFO estrutura pode conter valores de estado para JOB_STATUS_PAUSED ou JOB_STATUS_DELETING, que são relevantes apenas para esse trabalho de impressão específico. Os trabalhos de impressão podem se acumular em uma fila de impressão depois que eles tiverem desamarmado e ficarem com um estado de JOB_STATUS_PRINTED.

Cada uma dessas funções requer um identificador para uma impressora para identificar a Impressora desejada. Esse identificador é obtido da OpenPrinter função, que aceita uma cadeia de caracteres que contém o nome da impressora. Esse nome pode ser o nome local da impressora ou um nome de compartilhamento UNC em uma impressora de rede.

O código de exemplo a seguir demonstra como chamar a EnumJobs função corretamente para recuperar JOB_INFO estruturas e como chamar a GetPrinter função para recuperar PRINTER_INFO estruturas:

Código de exemplo

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;

}

Observação

Quando o pool de impressoras está habilitado no Windows NT, pode haver mais de um trabalho de impressão de uma fila de impressoras que relatará um status. Este código de exemplo não considera essa circunstância.