I have successfully managed to trigger a callback when a print job is initially requested on the local machine during spooling. However is there anyway with win32print
or something similar that may allow me to handle the event in which a print job is transferred to a print server or USB printer?
################################################################################
# Imports ######################################################################
################################################################################
from os.path import *
from printer import *
from watcher import *
from statvar import *
################################################################################
# Event Callback ###############################################################
################################################################################
def callback(code, event):
num = splitext(event)[0]
ext = splitext(event)[1]
if code == 1 and ext == '.SPL':
main(num.lstrip('0'))
################################################################################
# wx Event Handler #############################################################
################################################################################
def handling(*args):
wx.CallAfter(callback, *args)
################################################################################
# Create Listener ##############################################################
################################################################################
# listens to the spool directory for files
watch = Watcher(SPOOL_DIRECTORY, handling)
# set the appropriate flags for a listener
watch.flags = FILE_NOTIFY_CHANGE_FILE_NAME
################################################################################
# Start Listener ###############################################################
################################################################################
watch.start()
################################################################################
# Start wx App #################################################################
################################################################################
app = wx.App()
wx.Frame(None)
app.MainLoop()
################################################################################
################################################################################
################################################################################
The Python print() function takes in any number of parameters, and prints them out on one line of text. The items are each converted to text form, separated by spaces, and there is a single '\n' at the end (the "newline" char). When called with zero parameters, print() just prints the '\n' and nothing else.
In Windows, a built-in service called Print Spooler temporarily stores all print jobs until they're printed. These print jobs are stored by Windows as files in a folder associated with the Print Spooler service.
Here's an idea that worked on my computer (Windows 8). It's hardly fully fledged code, but it might get you going. You need to utilise the functions FindFirstPrinterChangeNotification
and FindNextPrinterChangeNotification
These are contained within winspool.drv
on the client side (irritatingly you can find them documented as being in spoolSS.dll
but this is server side - this diagram can clarify).
The list of events that can be listened for (and, importantly, their flag settings) are available from MSDN here. Initially I thought you wanted PRINTER_CHANGE_ADD_JOB
(0x00000100
), but I think you may actually want PRINTER_CHANGE_WRITE_JOB
(0x00000800
). This doesn't trigger as soon as the job starts spooling, but unfortunately it does seem to be triggered multiple times in the example where you send one document to a network printer.
Unfortunately, these APIs aren't exposed in the win32print
library. I think, therefore you have to dive into ctypes
. Here I haven't registered a callback as such, rather I listen for the notification and when triggered I call the function and start listening again in an infinite loop. The process is stalled while listening. If you need conventional callback functionality, you could either run this script in its own thread, or maybe this answer will not suit your needs.
Note - this simply listens for the print job being requested and then calls a function. If you want to extract information about the job being triggered, the code will become horrendous. Further note - it will trigger for a print job that is started and subsequently cancelled, but I imagine that's fine.
from ctypes import *
from ctypes.wintypes import HANDLE, LPSTR
def add_job_callback():
print('A job has just been sent to the printer this script is monitoring')
spl = windll.LoadLibrary('winspool.drv')
printer_name = 'KONICA MINOLTA PS Color Laser Class Driver'
# Put the name of your printer here - can be networked or any installed on your computer. Alternatively, set it to None to use the local printer server
#printer_name = None
hPrinter = HANDLE()
if printer_name:
spl.OpenPrinterA(c_char_p(printer_name), byref(hPrinter),None)
else:
spl.OpenPrinterA(None, byref(hPrinter),None)
print(hPrinter)
hjob = spl.FindFirstPrinterChangeNotification(hPrinter,0x00000100,0, None)
# 0x00000100 is a flags setting to set watch for only PRINTER_CHANGE_ADD_JOB
while True:
windll.kernel32.WaitForSingleObject(hjob,-1)
#When this function returns, the change that you're monitoring for has been observed, trigger the function
add_job_callback()
spl.FindNextPrinterChangeNotification(hjob, None, None, None)
Note there are some small differences between Python 2.7 and Python 3 here - e.g. the initialisation of the c_char_p
ctype
from a string. I've presented the simplest version I could here - it works in 2.7.
Postscript
I did all the heavy lifting and then found this answer, that is something of a duplicate. It has rather nicer code that handles unicode printer names and the like, but only looks at the default local print server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With