Abrufen der status eines Druckers und eines Druckauftrags

In diesem Artikel wird beschrieben, wie Sie die status eines Druckers und eines Druckauftrags mithilfe des Win32-Spoolers abrufen.

Ursprüngliche Produktversion: Win32-Spooler
Ursprüngliche KB-Nummer: 160129

Die status von Druckern und Druckaufträgen werden vom Win32-Spooler während des Despools eines Druckauftrags aktualisiert. Zu allen anderen Zeiten, wenn dieser Drucker nicht despoolt und keine Zustandsinformationen meldet, gilt der Drucker als bereit und im Leerlauf.

Wie von der Win32-API bezeichnet, besteht ein Drucker aus dem Druckertreiber, der Druckwarteschlange und dem Eingabe-/Ausgabepfad zum physischen Drucker. Das Betriebssystem behandelt einen physischen Drucker nur als Ziel eines Druckauftrags, der von einem Systemdrucker generiert und übergeben wird, der im restlichen Teil dieses Artikels als Drucker bezeichnet wird.

Der sichtbarste Teil eines Druckers ist eine Druckwarteschlange. Sie wird vom Druck-Manager oder den Druckerordnern in den Windows 95-Benutzeroberflächen verwaltet. Der Druckertreiber ist die Schnittstelle zum Drucker, die von Anwendungen zum Erstellen von Druckaufträgen über Drucker-DCs verwendet wird. Der E/A-Pfad für einen Drucker besteht aus mehreren Systemcodeebenen, die mit einem Portmonitor gipfeln.

Der Portmonitor ist die Schnittstelle zum physischen Drucker am Downstream-Ende eines Systemdruckers und ist für die Übertragung der Daten eines Druckauftrags über eine beliebige Verbindung mit dem physischen Drucker verantwortlich. Bei bidirektionalen Druckern ist der Portmonitor für die Übertragung von Daten an den und vom physischen Drucker verantwortlich. In dieser Verbindung und auf dem physischen Drucker treten Fehler auf. Es ist die Aufgabe des Portmonitors, diese Fehler zu melden.

Der Spooler fragt nicht den Zustand eines physischen Druckers ab, mit dem ein Drucker verbunden ist. Stattdessen bestimmt der Zustand eines physischen Druckers den Erfolg eines Druckauftrags zu dem Zeitpunkt, zu dem er über den Portmonitor entpoolt wird. Wenn bei diesem Vorgang ein Fehler auftritt, wird der Fehler vom Portmonitor gemeldet und in den status Informationen eines Druckauftrags aufgezeichnet. Der Spooler wiederum gibt angemessene Fehlerinformationen an die Druckerwarteschlange weiter.

Folglich meldet ein Systemdrucker keine status, wenn die Druckerwarteschlange leer ist. In diesem Zustand wird angenommen, dass der Drucker bereit ist, Druckaufträge zu akzeptieren. Dies ist eine gültige Annahme, auch wenn sich der physische Drucker in einem Fehlerzustand wie offline befindet. Das Betriebssystem betrachtet den Drucker als bereit, Druckaufträge zu akzeptieren, auch wenn er aus irgendeinem Grund die Lieferung an den physischen Drucker nicht abschließen kann. Ein solcher Umstand wird als Fehlerzustand im Betriebssystem betrachtet, der vom Benutzer behandelt werden muss. Es wird nicht als Fehler betrachtet, der der Anwendung gemeldet werden kann, die das Spooling des Druckauftrags erfolgreich abschließen darf.

Ermitteln des Zustands eines physischen Druckers

Es gibt eine grundlegende Voraussetzung, die wahr sein muss, um den Zustand eines physischen Druckers zu bestimmen: Der Spooler muss versuchen, einen Druckauftrag an den physischen Drucker zu senden. Dies ist das einzige Mal, dass der Zustand des Druckers vom Portmonitor gemeldet wird. Darüber hinaus können die aussagekräftigsten Informationen in den status Membern einer Struktur für diesen JOB_INFO bestimmten Druckauftrag gemeldet werden, da einige Portmonitore diese Werte direkt festgelegt haben.

Die JOB_INFO Strukturen enthalten ein Status -Element und ein pStatus -Element. Beide Member enthalten status Informationen zu einem Druckauftrag, der vom Portmonitor gemeldet wird. Diese beiden Member unterscheiden sich darin, dass der Status Member ein Bitfeld von Zuständen ist, das vordefinierte Werte enthält, während der pStatus Member ein Zeiger auf eine Zeichenfolge ist, die so gut wie alles enthalten kann. Diese Werte werden vom Win32 SDK und der WinSpool.h-Headerdatei dokumentiert. Der pStatus Member wird manchmal, aber nicht immer, auf eine beschreibende status Zeichenfolge festgelegt. Der Inhalt dieser Zeichenfolge wird von jedem Portmonitor definiert.

JOB_INFO -Strukturen werden von zwei API-Funktionen zurückgegeben: GetJob und EnumJobs. EnumJobs gibt ein Array von JOB_INFO Strukturen zurück, ohne dass der Aufrufer auf einen bestimmten Auftrag in der Druckerwarteschlange verweisen muss. Der Druckauftrag, der derzeit entpoolt (gedruckt) wird, enthält die status Informationen. Um diesen Auftrag im Array zu finden, durchsuchen Sie das Array von JOB_INFO Strukturen, um den Druckauftrag zu finden, dessen Status Member das JOB_STATUS_PRINTING Bit festgelegt hat.

Eine einfachere Methode zum Bestimmen des Druckers status besteht darin, den Status Member einer PRINTER_INFO Struktur zu untersuchen. Diese Struktur wird von der GetPrinter Funktion zurückgegeben. Dieser Ansatz hat einen Nachteil, da keine Zeichenfolgenmember in einer PRINTER_INFO Struktur vorhanden istpStatus, die möglicherweise detailliertere oder ausführlichere Zustandsinformationen bereitstellt. Es hat jedoch den Vorteil, dass ein Portmonitor einige der umfangreicheren Drucker status Bits der PRINTER_INFO Struktur festlegen kann. Der Standardportmonitor für Windows legt jedoch nicht mehr als das PRINTER_STATUS_ERROR Bit eines Druckerelements Status fest.

Hinweis

Die Status Member einer der beiden Strukturen können Zustandsinformationen enthalten, die nicht streng mit dem physischen Drucker verknüpft sind. Beispielsweise kann das Status Element der PRINTER_INFO Strukturen mit PRINTER_STATUS_PAUSED oder PRINTER_STATUS_PENDING_DELETIONfestgelegt werden, die für die Druckwarteschlange streng relevant sind. Außerdem kann der Status Member der JOB_INFO -Struktur Zustandswerte für JOB_STATUS_PAUSED oder JOB_STATUS_DELETINGenthalten, die nur für diesen bestimmten Druckauftrag relevant sind. Druckaufträge können sich nach dem Despoolen in einer Druckwarteschlange ansammeln und mit dem Status JOB_STATUS_PRINTEDbelassen werden.

Jede dieser Funktionen erfordert ein Handle für einen Drucker, um den gewünschten Drucker zu identifizieren. Dieses Handle wird von der OpenPrinter Funktion abgerufen, die eine Zeichenfolge akzeptiert, die den Namen des Druckers enthält. Dieser Name kann entweder der lokale Name des Druckers oder ein UNC-Freigabename für einen Netzwerkdrucker sein.

Im folgenden Beispielcode wird veranschaulicht, wie die EnumJobs Funktion ordnungsgemäß aufgerufen wird, um Strukturen abzurufen JOB_INFO , und wie die GetPrinter Funktion aufgerufen wird, um Strukturen abzurufen PRINTER_INFO :

Beispielcode

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;

}

Hinweis

Wenn das Druckerpooling unter Windows NT aktiviert ist, kann es sein, dass mehrere Druckaufträge aus einer Druckerwarteschlange entpoolt werden, die eine status melden. Dieser Umstand wird in diesem Beispielcode nicht berücksichtigt.