The other day I was trying to figure out a way to monitor the print queue on Windows. The task at hand was to keep track of what documents went to the printer and completely successfully. The idea was that when the print completed, the document would then be archived. To do this sort of thing, you need PyWin32 (AKA: Python for Windows extensions). In this article, we’ll look at a simple script that checks the print queue.
Here’s the code:
import time import win32print #---------------------------------------------------------------------- def print_job_checker(): """ Prints out all jobs in the print queue every 5 seconds """ jobs = [1] while jobs: jobs = [] for p in win32print.EnumPrinters(win32print.PRINTER_ENUM_LOCAL, None, 1): flags, desc, name, comment = p phandle = win32print.OpenPrinter(name) print_jobs = win32print.EnumJobs(phandle, 0, -1, 1) if print_jobs: jobs.extend(list(print_jobs)) for job in print_jobs: print "printer name => " + name document = job["pDocument"] print "Document name => " + document win32print.ClosePrinter(phandle) time.sleep(5) print "No more jobs!" #---------------------------------------------------------------------- if __name__ == "__main__": print_job_checker()
First off we import win32print and the time module. We need win32print to access the printer. We create a potentially infinite loop to keep checking for jobs in the print queue. If the jobs list is ever empty, that means there is nothing left in the print queue and the function will exit. In the code above we use win32print.EnumPrinters() to loop over the printers that are installed on the machine. The first argument is a flag (win32print.PRINTER_ENUM_LOCAL), the second is a name (or None in this case), and the third is information level. There are several flags we can use, such as PRINTER_ENUM_SHARED, PRINTER_ENUM_LOCAL or PRINTER_ENUM_CONNECTIONS. I went with PRINTER_ENUM_LOCAL because it was returning a printer name in a format that I could use with win32print’s OpenPrinter method. We do this to query the printer for information via a handle. To get a list of the print jobs, we call win32print.EnumJobs() with the print handle. Then we loop over them and print out the printer name and the document name. You don’t need to do all these prints, but I found it helpful when I was writing the code. For testing purposes, I recommend opening the print queue and setting it to “paused” so that you can prevent printing paper until you are ready. This allows you to still add items to the print queue that you can query.
I put a 5 seconds delay between checks to make sure there are no new updates to the queue. If there are print jobs, it checks the queue again. Otherwise it breaks out of the loop.
Hopefully you will find this piece of code useful for something you are doing. Enjoy!
Additional Information
- Tim Golden’s documentation for win32print
- An old thread about win32print on the PyWin32 mailing list
Pingback: Mike Driscoll: PyWin32 – How to Monitor the Print Queue | The Black Velvet Room
Pingback: PyWin32 – How to Monitor the Print Queue | Hello Linux
This would be really useful with something like Rainmeter.
hi get this error while running in python 2.7
Traceback (most recent call last):
File “C:UsersEdenDownloads102.py”, line 29, in
print_job_checker()
File “C:UsersEdenDownloads102.py”, line 15, in print_job_checker
phandle = win32print.OpenPrinter(name)
pywintypes.error: (1801, ‘OpenPrinter’, ‘The printer name is invalid.’)
I have never seen this error. Perhaps your printer has a strange name? Try printing out the name before passing it to OpenPrinter.
what name? I need to put value in ‘name’?
Inside the “for” loop, I extract the name of the printer. Print the name out BEFORE the OpenPrinter line.
Mike, I could really use some help on my Python project if you’re familiar with pywin32.
What kind of help? Perhaps you could send me a message via my blog’s contact form explaining what you’re having trouble with?
Mike, I think I’ve resolved that issue actually but I have another question. Assuming we have a MessageDialog, is there anyway to disallow interaction with all other foreground applications until the user responds to the dialog?
Hey Mike, it seems as if these print jobs are “created” locally during initial spooling ie. whenever you hit print, regardless of whether you’re online or offline, a job will locally be generated. How do I determine when a print job is actually received by the print server?
Mike, is there any way to wait for the print job to reach the print server and handle the event and trigger a callback at that moment.
I don’t know. You’d probably need to dig into Microsoft’s internals on MSDN to figure that out. I would try to see if anyone has done that sort of thing with .NET and then try to port their code to Python
import win32com.client
import time
strComputer = “.”
objWMIService = win32com.client.Dispatch(“WbemScripting.SWbemLocator”)
objSWbemServices = objWMIService.ConnectServer(strComputer,”rootcimv2″)
colItems = objSWbemServices.ExecQuery(“Select * from Win32_PrintJob”)
while True:
for objItem in colItems:
print (“Caption: “, objItem.Caption)
print (“Data Type: “, objItem.DataType)
print (“Description: “, objItem.Description)
print (“Document: “, objItem.Document)
print (“Driver Name: “, objItem.DriverName)
print (“Elapsed Time: “, objItem.ElapsedTime)
print (“Host Print Queue: “, objItem.HostPrintQueue)
print (“Install Date: “, objItem.InstallDate)
print (“Job Id: “, objItem.JobId)
print (“Job Status: “, objItem.JobStatus)
print (“Name: “, objItem.Name)
print (“Notify: “, objItem.Notify)
print (“Owner: “, objItem.Owner)
print (“Pages Printed: “, objItem.PagesPrinted)
print (“Parameters: “, objItem.Parameters)
print (“Print Processor: “, objItem.PrintProcessor)
print (“Priority: “, objItem.Priority)
print (“Size: “, objItem.Size)
print (“Start Time: “, objItem.StartTime)
print (“Status: “, objItem.Status)
print (“Status Mask: “, objItem.StatusMask)
print (“Time Submitted: “, objItem.TimeSubmitted)
print (“Total Pages: “, objItem.TotalPages)
print (“Until Time: “, objItem.UntilTime)
time.sleep(5)
how can I put this tracking code to see when it made ​​an impression and get the code??? Monitor the Print Queue
Hi Mike,
This code working for local prints(If I print from my computer).
But how can I monitor all documents have sent to printer from all users?
I don’t have a ready made solution. You would probably need to create some kind of monitoring solution. If your printers are on CUPS, you might be able to hook into that, for example.
Pingback: Batch printing multiple PDFs in Python – Windows Questions