Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Received Print Job Python

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()

################################################################################
################################################################################
################################################################################
like image 655
Malik Brahimi Avatar asked Dec 29 '15 21:12

Malik Brahimi


People also ask

How does print work in Python?

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.

Where are queued print jobs stored?

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.


1 Answers

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.

like image 51
J Richard Snape Avatar answered Oct 20 '22 00:10

J Richard Snape