Obtenir les status d’une imprimante et d’un travail d’impression

Cet article explique comment obtenir les status d’une imprimante et d’un travail d’impression à l’aide du spouleur Win32.

Version d’origine du produit : Spouleur Win32
Numéro de la base de connaissances d’origine : 160129

Les status des imprimantes et des travaux d’impression sont mis à jour par le spouleur Win32 pendant le dépoolage d’un travail d’impression. À tous les autres moments, lorsque cette imprimante n’est pas déspooling et ne signale aucune information d’état, l’imprimante est considérée comme prête et inactive.

Comme indiqué par l’API Win32, une imprimante est composée du pilote d’imprimante, de la file d’attente d’impression et du chemin d’entrée/sortie de l’imprimante physique. Le système d’exploitation traite une imprimante physique comme simplement la destination d’une tâche d’impression générée et transmise par une imprimante système, appelée imprimante dans le reste de cet article.

La partie la plus visible d’une imprimante est une file d’attente d’impression. Il est géré par le Gestionnaire d’impression ou les dossiers Imprimante dans les interfaces utilisateur de style Windows 95. Le pilote d’imprimante est l’interface de l’imprimante utilisée par les applications pour créer des travaux d’impression via des contrôleurs de domaine d’imprimante. Le chemin d’E/S d’une imprimante se compose de plusieurs couches de code système qui culminent avec un moniteur de port.

Le moniteur de port est l’interface de l’imprimante physique à l’extrémité du flux inférieur d’une imprimante système et est responsable du transfert des données d’un travail d’impression sur toute connexion à l’imprimante physique. Dans le cas des imprimantes bidirectionnelles, le moniteur de port est responsable du transfert des données vers et depuis l’imprimante physique. Cette connexion et l’imprimante physique sont l’endroit où des erreurs se produisent. Le moniteur de port doit signaler ces erreurs.

Le spouleur n’interroge pas l’état d’une imprimante physique à laquelle une imprimante est connectée. Au lieu de cela, l’état d’une imprimante physique détermine la réussite d’une tâche d’impression au moment où elle est dépoolée sur le moniteur de port. Si une erreur se produit dans ce processus, l’erreur est signalée par le moniteur de port et enregistrée dans les informations status d’un travail d’impression. Le spouleur, à son tour, propage des informations d’erreur raisonnables à la file d’attente de l’imprimante.

Par conséquent, une imprimante système ne signale aucune status lorsque la file d’attente d’imprimantes est vide. Dans cet état, l’imprimante est supposée être prête à accepter des travaux d’impression. Il s’agit d’une hypothèse valide même si l’imprimante physique est dans un état d’erreur tel que hors ligne. Le système d’exploitation considère que l’imprimante est prête à accepter des travaux d’impression, même si, pour une raison quelconque, elle ne peut pas être remise à l’imprimante physique. Une telle situation est considérée comme un état d’erreur dans le système d’exploitation qui doit être résolu par l’utilisateur. Elle n’est pas considérée comme une erreur pouvant être signaler à l’application qui est autorisée à effectuer correctement le spoulage du travail d’impression.

Déterminer l’état d’une imprimante physique

Il existe un principe fondamental qui doit être vrai pour déterminer l’état d’une imprimante physique : le spouleur doit tenter d’envoyer un travail d’impression à l’imprimante physique. Il s’agit de la seule fois où l’état de l’imprimante est signalé par le moniteur de port. En outre, les informations les plus significatives peuvent être signalées dans le status membres d’une JOB_INFO structure pour ce travail d’impression particulier, car certains moniteurs de port auront défini ces valeurs directement.

Les JOB_INFO structures contiennent un Status membre et un pStatus membre. Les deux membres contiennent status informations d’un travail d’impression signalé par le moniteur de port. Ces deux membres diffèrent en ce que le Status membre est un champ de bits d’états qui contient des valeurs prédéterminées, tandis que le pStatus membre est un pointeur vers une chaîne qui peut contenir à peu près n’importe quoi. Ces valeurs sont documentées par le Kit de développement logiciel (SDK) Win32 et le fichier d’en-tête WinSpool.h. Le pStatus membre est parfois, mais pas toujours, défini sur une chaîne de status descriptive. Le contenu de cette chaîne est défini par chaque moniteur de port.

JOB_INFO les structures sont retournées par deux fonctions d’API : GetJob et EnumJobs. EnumJobs retourne un tableau de JOB_INFO structures sans exiger que l’appelant référence un travail particulier dans la file d’attente Printer. Le travail d’impression en cours de dépooling (impression) contient les informations status. Pour trouver ce travail dans le tableau, recherchez le tableau de JOB_INFO structures pour localiser le travail d’impression dont Status le membre a le JOB_STATUS_PRINTING bit défini.

Une méthode plus simple pour déterminer l’imprimante status consiste à examiner le Status membre d’une PRINTER_INFO structure. Cette structure est retournée par la GetPrinter fonction . Cette approche présente un inconvénient dans le fait qu’il n’existe aucun pStatus membre de chaîne dans une PRINTER_INFO structure susceptible de fournir des informations d’état plus détaillées ou plus complètes. Toutefois, il existe un avantage dans le fait qu’un moniteur de port peut définir certains des bits d’imprimante les plus étendus status de la PRINTER_INFO structure. Toutefois, le moniteur de port par défaut pour Windows ne définit pas plus que le PRINTER_STATUS_ERROR bit du membre d’une Status imprimante.

Remarque

Les Status membres de l’un ou l’autre ensemble de structures peuvent contenir des informations d’état qui ne sont pas strictement liées à l’imprimante physique. Par exemple, le Status membre des PRINTER_INFO structures peut être défini avec PRINTER_STATUS_PAUSED ou PRINTER_STATUS_PENDING_DELETION, qui sont strictement pertinents pour la file d’attente d’impression. En outre, le Status membre de la JOB_INFO structure peut contenir des valeurs d’état pour JOB_STATUS_PAUSED ou JOB_STATUS_DELETING, qui sont pertinentes uniquement pour ce travail d’impression particulier. Les travaux d’impression peuvent s’accumuler dans une file d’attente d’impression une fois qu’ils ont été dépoolés et resteraient avec l’état JOB_STATUS_PRINTED.

Chacune de ces fonctions nécessite un handle pour une imprimante pour identifier l’imprimante souhaitée. Ce handle est obtenu à partir de la OpenPrinter fonction qui accepte une chaîne contenant le nom de l’imprimante. Ce nom peut être le nom local de l’imprimante ou un nom de partage UNC sur une imprimante réseau.

L’exemple de code suivant montre comment appeler correctement la EnumJobs fonction pour récupérer des JOB_INFO structures et comment appeler la GetPrinter fonction pour récupérer des PRINTER_INFO structures :

Exemple de code

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;

}

Remarque

Lorsque le regroupement d’imprimantes est activé sur Windows NT, plusieurs travaux d’impression peuvent être supprimés d’une file d’attente Imprimante pour signaler un status. Cet exemple de code ne tient pas compte de cette circonstance.