4

I need to print some information directly (without user confirmation) and I'm using Python and the win32print module.

I've already read the whole Tim Golden win32print page (even read the win32print doc, which is small) and I'm using the same example he wrote there himself, but I just print nothing.

If I go to the interactive shell and make one step at a time, I get the document on the printer queue (after the StartDocPrinter), then I get the document size (after the StartPagePrinter, WritePrinter, EndPagePrinter block) and then the document disappear from the queue (after the EndDocPrinter) without printing.

I'm aware of the ShellExecute method Tim Golden showed. It works here, but it needs to create a temp file and it prints this filename, two things I don't want.

Any ideas? Thanks in advance.

This is the code I'm testing (copy and paste of Tim Golden's):

import os, sys  
import win32print
import time
printer_name = win32print.GetDefaultPrinter()
if sys.version_info >= (3,):
    raw_data = bytes ("This is a test", "utf-8")
else:
    raw_data = "This is a test"

hPrinter = win32print.OpenPrinter (printer_name)
try:
    hJob = win32print.StartDocPrinter (hPrinter, 1, ("test of raw data", None, "RAW"))
    try:
        win32print.StartPagePrinter (hPrinter)
        win32print.WritePrinter (hPrinter, raw_data)
        win32print.EndPagePrinter (hPrinter)
    finally:
        win32print.EndDocPrinter (hPrinter)
finally:
    win32print.ClosePrinter (hPrinter)

[EDIT]

I installed a pdf printer in my computer to test with another printer (CutePDF Writer) and I could generate the test of raw data.pdf file, but when I look inside there is nothing. Meaning: all commands except WritePrinter appears to be doing what they were supposed to do. But again, as I said in the comments, WritePrinter return the correct amount of bytes that were supposed to be written to the printer. I have no other idea how to solve this, but just comproved there is nothing wrong with my printer.

marcelocra
  • 2,094
  • 2
  • 24
  • 37
  • To see if there's a problem and get an idea of what it is, change the exception handling so it prints any that occur to the console instead of ignoring them with `finally`s. – martineau Jan 24 '13 at 17:30
  • Just tested that. There are no exceptions occurring. – marcelocra Jan 24 '13 at 17:59
  • Actually the code does not handle the exceptions, so if I got any it would have been shown in the console, i guess. But thanks anyway =D. – marcelocra Jan 24 '13 at 18:09
  • True, sorry. Well, each of the native `win32` functions you're calling returns something and I'm not sure if the `win32print` module trys to translate them into exceptions or not when something wrong -- so I'd start checking each one's return value. You can see what the native functions return by consulting the documentation starting with the [StartDocPrinter()](http://msdn.microsoft.com/en-us/library/windows/desktop/dd145115%28v=vs.85%29.aspx) function which has links to all the others. – martineau Jan 24 '13 at 18:48
  • According to the values specified there, nothing wrong with my return values either. Though, there is no guarantee that this link you found would be accurate for Python, once it's made for C++. – marcelocra Jan 24 '13 at 19:11
  • Actually the second link I posted contains the return values for Python api. I just tested again and there is nothing wrong. The most strange thing is that the function that writes the information to the printer (`WritePrinter`) [returns the number of bytes written to the printer](http://timgolden.me.uk/pywin32-docs/win32print__WritePrinter_meth.html) and it returns the correct number of bytes, but nothing is printed.... – marcelocra Jan 24 '13 at 19:26
  • 1
    Is it possible that the printer simply doesn't know how to respond to raw data? Usually the driver builds the page in the printer's native language, but that's bypassed in raw mode. – Mark Ransom Jan 24 '13 at 20:59
  • I guess that's possible, yes. In the win32print documentation, [the last line of this page](http://timgolden.me.uk/pywin32-docs/win32print__StartDocPrinter_meth.html) it's said that the printer might ignore the request. I'm still looking into it, but the question is answered for now. If I find anything else I'll post here. – marcelocra Jan 25 '13 at 16:01
  • I found out that it prints raw data just fine on my HP LJ P2035 but not on HP LJ P1005 on the same PC. I think it is what @MarkRansom said. I tried all `printing processing` options from RAW, ENF etc... No luck with 1005 – Hrvoje T Jun 16 '17 at 10:52
  • I just found out that my HP LJ P1005 is non-PCL printer and is host-based which means that PC and printer driver is taking care of printing. Could this mean that it is not capable of printing raw data? – Hrvoje T Jun 16 '17 at 12:29
  • 1
    @HrvojeT that's exactly what it means. It's a cost-cutting measure, the printer doesn't need the intelligence to convert raw data to dots. – Mark Ransom Jun 16 '17 at 13:27
  • @MarkRansom So I can print PCL file to a non-PCL printer? It is a driver on a host PC who is doing a job for converting data to dots and sends that to the printer? – Hrvoje T Jun 19 '17 at 05:15
  • @HrvojeT you'd need an application that can interpret PCL and convert it to Windows drawing commands - I don't think a driver would do that on its own. Check out Ghostscript. – Mark Ransom Jun 19 '17 at 13:07

3 Answers3

4

I'm still looking for the best way to do this, but I found an answer that satisfy myself for the problem that I have. In Tim Golden's site (linked in question) you can find this example:

import win32ui
import win32print
import win32con

INCH = 1440

hDC = win32ui.CreateDC ()
hDC.CreatePrinterDC (win32print.GetDefaultPrinter ())
hDC.StartDoc ("Test doc")
hDC.StartPage ()
hDC.SetMapMode (win32con.MM_TWIPS)
hDC.DrawText ("TEST", (0, INCH * -1, INCH * 8, INCH * -2), win32con.DT_CENTER)
hDC.EndPage ()
hDC.EndDoc ()

I adapted it a little bit after reading a lot of the documentation. I'll be using win32ui library and TextOut (device context method object).

import win32ui
# X from the left margin, Y from top margin
# both in pixels
X=50; Y=50
multi_line_string = input_string.split()
hDC = win32ui.CreateDC ()
hDC.CreatePrinterDC (your_printer_name)
hDC.StartDoc (the_name_will_appear_on_printer_spool)
hDC.StartPage ()
for line in multi_line_string:
     hDC.TextOut(X,Y,line)
     Y += 100
hDC.EndPage ()
hDC.EndDoc ()

I searched in meta stackoverflow before answering my own question and here I found it is an encouraged behavior, therefore I'm doing it. I'll wait a little more to see if I get any other answer.

Community
  • 1
  • 1
marcelocra
  • 2,094
  • 2
  • 24
  • 37
2
# U must install pywin32 and import modules:
import win32print, win32ui, win32con  
# X from the left margin, Y from top margin 
# both in pixels
X=50; Y=50
# Separate lines from Your string 
# for example:input_string and create 
# new string for example: multi_line_string 
multi_line_string = input_string.splitlines()  
hDC = win32ui.CreateDC ()
# Set default printer from Windows:
hDC.CreatePrinterDC (win32print.GetDefaultPrinter ())
hDC.StartDoc (the_name_will_appear_on_printer_spool)
hDC.StartPage ()
for line in multi_line_string:
     hDC.TextOut(X,Y,line)
     Y += 100
hDC.EndPage ()
hDC.EndDoc ()
#I like Python
1

The problem is the driver Version. If the Version is 4 you need to give XPS_PASS instead of RAW, here is a sample.

drivers = win32print.EnumPrinterDrivers(None, None, 2)
hPrinter = win32print.OpenPrinter(printer_name)
printer_info = win32print.GetPrinter(hPrinter, 2)
for driver in drivers:
    if driver["Name"] == printer_info["pDriverName"]:
        printer_driver = driver
raw_type = "XPS_PASS" if printer_driver["Version"] == 4 else "RAW"

try:
  hJob = win32print.StartDocPrinter(hPrinter, 1, ("test of raw data", None, raw_type))
  try:
    win32print.StartPagePrinter(hPrinter)
    win32print.WritePrinter(hPrinter, raw_data)
    win32print.EndPagePrinter(hPrinter)
  finally:
    win32print.EndDocPrinter(hPrinter)
finally:
  win32print.ClosePrinter(hPrinter)
milouk
  • 171
  • 1
  • 3
  • 11