Obtener el estado de una impresora y un trabajo de impresión

En este artículo se presenta cómo obtener el estado de una impresora y un trabajo de impresión mediante la cola win32.

Versión original del producto: Win32 Spooler
Número de KB original: 160129

La cola win32 actualiza el estado de las impresoras y los trabajos de impresión durante el despool de un trabajo de impresión. En cualquier otro momento, cuando esa impresora no se desagrupa y no informa de información de estado, se considera que la impresora está lista e inactiva.

Como hace referencia la API win32, una impresora se compone del controlador de impresora, la cola de impresión y la ruta de acceso de entrada y salida a la impresora física. El sistema operativo trata una impresora física como simplemente el destino de un trabajo de impresión generado y pasado a través de una impresora del sistema, a la que se hace referencia en el resto de este artículo como una impresora.

La parte más visible de una impresora es una cola de impresión. Se administra mediante el Administrador de impresión o las carpetas Impresora en las interfaces de usuario de estilo Windows 95. El controlador de impresora es la interfaz de la impresora que usan las aplicaciones para crear trabajos de impresión a través de controladores de dominio de impresora. La ruta de acceso de E/S de una impresora consta de varias capas de código del sistema que culminan con un monitor de puerto.

El monitor de puerto es la interfaz de la impresora física en el extremo de flujo descendente de una impresora del sistema y es responsable de transferir los datos de un trabajo de impresión a través de cualquier conexión que exista a la impresora física. En el caso de las impresoras bidireccionales, el monitor de puertos sería responsable de transferir datos hacia y desde la impresora física. Esta conexión, y la impresora física, son donde se producen errores. Es el trabajo del monitor de puertos notificar esos errores.

Spooler no consulta el estado de una impresora física a la que está conectada una impresora. En su lugar, el estado de una impresora física determina el éxito de un trabajo de impresión en el momento en que se desagrupa en el monitor de puertos. Si se produce algún error en este proceso, el monitor de puerto notifica el error y se registra en la información de estado de un trabajo de impresión. A su vez, Spooler propaga información de error razonable a la cola de impresoras.

Por lo tanto, una impresora del sistema no notifica ningún estado cuando la cola de impresoras está vacía. En este estado, se supone que la impresora está lista para aceptar trabajos de impresión. Se trata de una suposición válida incluso si la impresora física está en un estado de error, como fuera de línea. El sistema operativo considera que la impresora está lista para aceptar trabajos de impresión incluso si, por algún motivo, no puede completar la entrega a la impresora física. Esta circunstancia se considera un estado de error en el sistema operativo que debe abordar el usuario. No se considera que se pueda notificar un error a la aplicación que pueda completar correctamente la cola del trabajo de impresión.

Determinación del estado de una impresora física

Hay una premisa fundamental que debe ser verdadera para determinar el estado de una impresora física: la cola debe intentar enviar un trabajo de impresión a la impresora física. Esta es la única vez que el monitor de puerto notifica el estado de la impresora. Además, la información más significativa se puede notificar en los miembros de estado de una JOB_INFO estructura para ese trabajo de impresión determinado porque algún monitor de puertos habrá establecido estos valores directamente.

Las JOB_INFO estructuras contienen un Status miembro y un pStatus miembro. Ambos miembros contienen información de estado de un trabajo de impresión notificado por el monitor de puertos. Estos dos miembros difieren en que el Status miembro es un campo bit de estados que contiene valores predeterminados, mientras que el pStatus miembro es un puntero a una cadena que podría contener casi cualquier cosa. Estos valores se documentan mediante el SDK de Win32 y el archivo de encabezado WinSpool.h. A pStatus veces, el miembro se establece, pero no siempre, en una cadena de estado descriptivo. Cada monitor de puerto define el contenido de esta cadena.

JOB_INFO Las estructuras se devuelven mediante dos funciones de API: GetJob y EnumJobs. EnumJobs devuelve una matriz de estructuras sin necesidad de JOB_INFO que el autor de la llamada haga referencia a un trabajo determinado en la cola de impresoras. El trabajo de impresión que actualmente está desagrupando (impresión) contiene la información de estado. Para buscar este trabajo en la matriz, busque en la matriz de JOB_INFO estructuras para buscar el trabajo de impresión cuyo Status miembro tiene el conjunto de JOB_STATUS_PRINTING bits.

Un método más sencillo para determinar el estado de la impresora es examinar el Status miembro de una PRINTER_INFO estructura. La función devuelve GetPrinter esta estructura. Hay una desventaja en este enfoque en que no hay ningún pStatus miembro de cadena en una PRINTER_INFO estructura que pueda proporcionar información de estado más detallada o extensa. Sin embargo, hay una ventaja en que un monitor de puerto puede establecer algunos de los bits de estado de impresora más extensos de la PRINTER_INFO estructura. Sin embargo, el monitor de puerto predeterminado para Windows no establece más que el PRINTER_STATUS_ERROR bit del miembro de Status una impresora.

Nota:

Los Status miembros de cualquier conjunto de estructuras pueden contener información de estado que no esté estrictamente relacionada con la impresora física. Por ejemplo, el Status miembro de las PRINTER_INFO estructuras se puede establecer con PRINTER_STATUS_PAUSED o PRINTER_STATUS_PENDING_DELETION, que son estrictamente pertinentes para la cola de impresión. Además, el Status miembro de la JOB_INFO estructura puede contener valores de estado para JOB_STATUS_PAUSED o JOB_STATUS_DELETING, que solo son pertinentes para ese trabajo de impresión determinado. Los trabajos de impresión pueden acumularse en una cola de impresión después de que se hayan desagrupado y se quedarán con un estado de JOB_STATUS_PRINTED.

Cada una de estas funciones requiere un identificador para una impresora para identificar la impresora deseada. Este identificador se obtiene de la OpenPrinter función , que acepta una cadena que contiene el nombre de la impresora. Este nombre puede ser el nombre local de la impresora o un nombre compartido UNC para una impresora de red.

En el código de ejemplo siguiente se muestra cómo llamar a la EnumJobs función correctamente para recuperar JOB_INFO estructuras y cómo llamar a la GetPrinter función para recuperar PRINTER_INFO estructuras:

Código de ejemplo

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;

}

Nota:

Cuando la agrupación de impresoras está habilitada en Windows NT, es posible que haya más de un trabajo de impresión que desagrupe desde una cola de impresoras que notifique un estado. Este código de ejemplo no tiene en cuenta esa circunstancia.