GH Python pywin32 error: "Runtime error (ImportException): No module named win32api"

Hi everyone,

I am trying to print a file directly from the GHPython component, getting past the print dialog window.

According to many pages on the internet I need to install the pywin32 module to do so. So I did successfully.

Tim Golden's Python Stuff: Print
How to print directly without showing print dialog using python script in windows? - Stack Overflow

From Python Shell this seems to be working ok.

pywin32_working

While inside GH I get this:

Thanks for any help in figuring this one out.

PrintFileTest.gh (2.9 KB)

import win32print

if x == 1:
    printername = win32print.GetDefaultPrinter ()
    print (printername)

Hi,
Are you sure you are using the same Python interpreter in the two places? You can check using this line in both:

import sys
print(sys.version)

The standard rhino and grasshopper components use Ironpython and not your system Python interpreter.

And in addition to it being IronPython, the IronPython distribution we use implements Python 2.7, not 3.x.

@Dancergraham and @nathanletwory thank you guys.

Indeed I get 2.7.0 when running print(sys.version) inside GH
and 3.7.2 when on Python Shell.

What should I do? Will downloading Python 2.7 solve the problem?

I don’t think you can install packages into ironpython unless they are pure Python packages which you can just put into your site packages folder.
You can print from rhino with rs.command(). For example:

Otherwise you will need to access .Net methods - I don’t know anything about .Net so can’t help you here.

this seems like a bit of a long walk to get the default printer from within a GHPython component…but it works.

clr.AddReference("System.Management")
from System.Management import ManagementObjectSearcher

DefaultPrnt = []
OtherPrnt = []

objMgt = ManagementObjectSearcher("Select * from Win32_Printer")
for result in objMgt.Get():
    if result.GetPropertyValue("Default") == True:
        DefaultPrnt.append(result.GetPropertyValue("Caption").ToString())
    else:
        OtherPrnt.append(result.GetPropertyValue("Caption").ToString())
    
a = DefaultPrnt
b = OtherPrnt

Hi Chris, thanks. Unfortunately this is just an example, and the script I found uses some more functions from the pywin32 module.

The ultimate goal is to automatically send to print a file when True, with no additional user input.

Maybe someone on this forum knows an easier way. Or maybe it is just no possible from within GH.

How to print directly without showing print dialog using python script in windows? - Stack Overflow

import win32print, win32ui, win32gui
import win32con, pywintypes

# create a dc (Device Context) object (actually a PyCDC)
dc = win32ui.CreateDC()

# convert the dc into a "printer dc"

# get default printer
printername = win32print.GetDefaultPrinter ()
# leave out the printername to get the default printer automatically
dc.CreatePrinterDC(printername)

# you need to set the map mode mainly so you know how
# to scale your output.  I do everything in points, so setting
# the map mode as "twips" works for me.
dc.SetMapMode(win32con.MM_TWIPS) # 1440 per inch

# here's that scaling I mentioned:
scale_factor = 20 # i.e. 20 twips to the point

# start the document.  the description variable is a string
# which will appear in the print queue to identify the job.
dc.StartDoc('Win32print test')

# to draw anything (other than text) you need a pen.
# the variables are pen style, pen width and pen color.
pen = win32ui.CreatePen(0, int(scale_factor), 0)

# SelectObject is used to apply a pen or font object to a dc.
dc.SelectObject(pen)

# how about a font?  Lucida Console 10 point.
# I'm unsure how to tell if this failed.
font = win32ui.CreateFont({
    "name": "Lucida Console",
    "height": int(scale_factor * 10),
    "weight": 400,
})

# again with the SelectObject call.
dc.SelectObject(font)

# okay, now let's print something.
# TextOut takes x, y, and text values.
# the map mode determines whether y increases in an
# upward or downward direction; in MM_TWIPS mode, it
# advances up, so negative numbers are required to
# go down the page.  If anyone knows why this is a
# "good idea" please email me; as far as I'm concerned
# it's garbage.
dc.TextOut(scale_factor * 72,
    -1 * scale_factor * 72,
    "Testing...")

# for completeness, I'll draw a line.
# from x = 1", y = 1"
dc.MoveTo((scale_factor * 72, scale_factor * -72))
# to x = 6", y = 3"
dc.LineTo((scale_factor * 6 * 72, scale_factor * 3 * -72))

# must not forget to tell Windows we're done.
dc.EndDoc()

I’d think you have better luck using .NET directly, as @chanley alluded to. A quick search on the internet gave me for instance

The example shows how to use the Graphics context to do the drawing.