GetPrinterJobs
Una función (escrita en C++) para saber el número de trabajos pendientes de imprimir y el número total de páginas (nuevo)
Publicado: 09/Jun/2001
Actualizado: 13/Jun/2001 (Número de páginas pendientes de
imprimir)
Y yo que me quejo de las consultas...
Pues eso, que esta mañana recibí una consulta sobre cómo saber el número de trabajos pendientes de imprimir de una impresora.
Estuve buscando en la MSDN Library y estuve viendo las funciones del API y los tipos definidos que se podrían usar para obtener esa información, pero... al intentar adaptarlo al Visual Basic... nada de nada, (aparte de algún que otro desplante... por fallo de acceso a la memoria y esas cosas que suelen ocurrir cuando se accede al API)... seguí buscando y me encontré con un ejemplo en C/C++ que, entre otras cosas, mostraba cómo obtener el número de trabajos pendientes de imprimir, (que era lo que buscaba), pero hacía uso de "reserva de memoria" y otras cosas que el Visual Basic tiene vetado... Así que, me lancé a "desempolvar" algunas pruebas que hice con el CBuilder (sí, de Borland) y me puse en la tarea de adaptar el "trozo" de código C que encontré.Y este es el resultado:
(Perdona toda esta cháchara, pero es que si no... pues iba a ser el artículo como muy corto...)
Para usar la función:
MsgBox "Número de trabajos pendientes de la impresora " & Printer.DeviceName & _ " es: " & GetPrinterJobs(Printer.DeviceName)Aquí tienes el código de la función (en C/C++), así como el que habría que usar desde Visual Basic.
/*----------------------------------------------------------------------------- gsPrinterJobs.dll (08/Jun/01) DLL para devolver el número de trabajos pendiente de una impresora Basado en un ejemplo de la MSDN Library ©Guillermo 'guille' Som, 2001 //----------------------------------------------------------------------------- */ #include <windows.h> /* Devuelve el número de trabajos pendientes de la impresora indicada o -1 si se produce algún error. El parámetro será el nombre de la impresora (Printer.DeviceName) */ extern "C" WINBASEAPI DWORD WINAPI FAR PASCAL _export GetPrinterJobs(BSTR bstrDeviceName) { HANDLE hPrinter; DWORD cByteNeeded; PRINTER_INFO_2 *pPrinterInfo = NULL; LPSTR strSrcByVal; DWORD Fallo = -1; // Copia de la cadena en formato C/C++ strSrcByVal = (LPSTR)bstrDeviceName; // Abrir la impresora if (!OpenPrinter(strSrcByVal, &hPrinter, NULL)) return Fallo; // Obtener el tamaño del buffer if (!GetPrinter(hPrinter, 2, NULL, 0, &cByteNeeded)) { // Si da otro error distinto del esperado... if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) return Fallo; } // Reserva memoria para el buffer pPrinterInfo = (PRINTER_INFO_2 *)malloc(cByteNeeded); if (!(pPrinterInfo)) // fallo en la reserva de memoria return Fallo; // Obtener la información de la impresora if (!GetPrinter(hPrinter, 2, (LPSTR)pPrinterInfo, cByteNeeded, &cByteNeeded)) { // fallo en el acceso al puntero free(pPrinterInfo); pPrinterInfo = NULL; return Fallo; } // Cerrar la impresora ClosePrinter(hPrinter); // Devolver el valor de cJobs return (DWORD)pPrinterInfo->cJobs; }Ejemplo de cómo usar esta función en Visual Basic:
'------------------------------------------------------------------------------ ' Prueba para saber los trabajos pendientes de una impresora (08/Jun/01) ' Usando una DLL escrita en CBuilder ' ' ©Guillermo 'guille' Som, 2001 '------------------------------------------------------------------------------ Option Explicit ' Declaración de la función Private Declare Function GetPrinterJobs Lib "gsPrinterJobs.dll" _ (ByVal sDeviceName As String) As Long Private Sub cmdInfo_Click() Dim s As String Dim n As Long Const Fallo As Long = -1& ' s = cboPrinters.Text ' n = GetPrinterJobs(s) If n = Fallo Then List1.AddItem "Fallo al llamar a la función" Else List1.AddItem s List1.AddItem "Número de trabajos pendientes: " & n End If End Sub Private Sub Form_Load() ' Enumerar las impresoras disponibles Dim tPrinter As Printer ' ' Añadir las impresoras disponibles For Each tPrinter In Printers cboPrinters.AddItem tPrinter.DeviceName Next ' Asignar la variable de la impresora seleccionada Set tPrinter = Printer If cboPrinters.ListCount > 0 Then cboPrinters.Text = tPrinter.DeviceName End If End SubEste es el aspecto del formulario:
Espero que te pueda ser de utilidad.
Nos vemos.
Guillermo
P.S.
Aquí tienes el código C/C++ y del ejemplo en VB: PrinterJobs.zip 59.6KB (actualizado el 13/Jun/2001)13/Jun/2001: Número de páginas pendientes de imprimir.
Le he añadido una nueva función a la librería, en este caso es para saber también el número de páginas que quedan por imprimir (además del número de trabajos pendientes)
He de avisar de que no todas las impresoras tienen esta característica, la he probado en una HP 840C y funciona bien, (como podrás comprobar en la imagen).
La nueva función se llama: GetNumPages y se declara de la siguiente forma:
fíjate que el segundo parámetro es ByRef, para que se devuelva en la variable el número de trabajos pendientes.Private Declare Function GetNumPages Lib "gsPrinterJobs.dll" _ (ByVal sDeviceName As String, ByRef NumJobs As Long) As LongPara usarla:
Dim s As String Dim n As Long Const Fallo As Long = -1& Dim p As Long ' s = cboPrinters.Text ' ' Número de trabajos pendientes y número de páginas (11/Jun/01) ' n = GetNumPages(s, p) If n = Fallo Then List1.AddItem "Fallo al llamar a la función" Else List1.AddItem s List1.AddItem "Número de trabajos pendientes: " & p & ", páginas: " & n End If
Aquí tienes el código en C/C++ de la nueva función:
/* Función para leer el número de páginas pendientes de imprimir (11/Jun/01) Basado en un ejemplo de la MSDN Library: How To Call Win32 Spooler Enumeration APIs Properly */ // Devuelve el número de páginas por imprimir y en el segundo parámetro, // (por referencia) el número de trabajos pendientes extern "C" WINBASEAPI DWORD WINAPI FAR PASCAL _export GetNumPages(BSTR bstrDeviceName, DWORD *NumJobs) { HANDLE hPrinter; DWORD dwNeeded, dwReturned, i; JOB_INFO_1 *pJobInfo; LPTSTR szPrinterName; DWORD Fallo = -1; DWORD TotalPaginas=0; // Copia de la cadena en formato C/C++ szPrinterName = (LPSTR)bstrDeviceName; // You need a printer handle, open the printer if( ! OpenPrinter( szPrinterName, &hPrinter, NULL ) ) return Fallo; // First you call EnumJobs() to find out how much memory you need if( ! EnumJobs( hPrinter, 0, 0xFFFFFFFF, 1, NULL, 0, &dwNeeded, &dwReturned ) ) { // It should have failed, but if it failed for any reason other // than "not enough memory", you should bail out if( GetLastError() != ERROR_INSUFFICIENT_BUFFER ) { ClosePrinter( hPrinter ); return Fallo; } } // Allocate enough memory for the JOB_INFO_1 structures plus // the extra data - dwNeeded from the previous call tells you // the total size needed if( (pJobInfo = (JOB_INFO_1 *)malloc( dwNeeded )) == NULL ) { ClosePrinter( hPrinter ); return Fallo; } // Call EnumJobs() again and let it fill out our structures if( ! EnumJobs( hPrinter, 0, 0xFFFFFFFF, 1, (LPBYTE)pJobInfo, dwNeeded, &dwNeeded, &dwReturned ) ) { ClosePrinter( hPrinter ); free( pJobInfo ); return Fallo; } // You're done with the printer handle, close it ClosePrinter( hPrinter ); // dwReturned tells how many jobs there are // Here, you'll simply display the number of jobs found *NumJobs = dwReturned; TotalPaginas = 0; // It's easy to loop through the jobs and access each one for(i=0;i<dwReturned;i++) { // pJobInfo[i] is a JOB_INFO_1 struct for that job // so here you could do whatever you want for each job TotalPaginas = TotalPaginas + pJobInfo[i].TotalPages; } // Clean up free( pJobInfo ); return (DWORD)TotalPaginas; }Puedes usar el link de arriba, ya que el fichero está actualizado.
¡Que lo disfrutes!
Nos vemos.
Guillermo