Version 16 of Printing text files under Windows

Updated 2004-03-20 22:19:14

Keith Vetter 2003-09-10: Today I wanted to print a simple text from within tcl. I thought it should be easy--it is just exec notepad /p myfile.txt. But to do it properly turned out to be quite difficult.

I'll explain why, but the ultimate command you need to executes is this:

   exec c:/winnt/system32/cmd.exe /c start /min c:/winnt/system32/notepad /p myfile.txt

First off, you need to look in the registry and find the print command for text files:

    package require registry
    set app [registry get {HKEY_CLASSES_ROOT\.txt} {}]
    set pcmd [registry get HKEY_CLASSES_ROOT\\$app\\shell\\print\\command {}]
      NB. pcmd => %SystemRoot%\system32\NOTEPAD.EXE /p %1

Now put our file name for %1.

    set fname myfile.txt
    regsub -all {%1} $pcmd [file normalize $fname] pcmd
      NB. pcmd => %SystemRoot%\system32\NOTEPAD.EXE /p c:/temp/myfile.txt

So far so good, but now when I try to execute it there are two problems. First, the %SystemRoot% needs to be handled, and second, the notepad window flashes momentarily. Luckily, both problems can be handled by simply using start /min to run the command.

     set command "[auto_execok start] /min $pcmd"
     exec $command &

WRONG -- this needs to be broken into words with eval

     eval exec $command &

WRONG -- the backslashes in $pcmd are doubly interpreted

     set command "[auto_execok start] /min [regsub -all {\\} $pcmd {\\\\}]"
     eval exec $command &

YEAH! (and don't try replacing the backslashes with forward slashes or 4DOS/4NT won't work)

Putting it all together, here's a short procedure to print a text file on windows (w/ no error checking and tested only on Win2k):

 proc PrintText {fname} {
    package require registry
    set app [registry get {HKEY_CLASSES_ROOT\.txt} {}]
    set pcmd [registry get HKEY_CLASSES_ROOT\\$app\\shell\\print\\command {}]
    regsub -all {%1} $pcmd [file normalize $fname] pcmd
    set command "[auto_execok start] /min [regsub -all {\\} $pcmd {\\\\}]"
    eval exec $command &
 }

This will not work on W2k, if pcmd contains spaces, and is quoted with "", as start will interpret it as the window title. (it works on Win9x). Adding a "" to the command line helps.

KPV could you explain your fix more. Or perhaps you could insert a dummy window title.

HZe I have had similar problems with the command start and the usage of quotes "". The most robust solution I found is to convert all filenames to Windows shortnames by

 set filename [file attribute $filename -shortname]

and don't include it in quotes. Otherwise I didn't get it to work on Windows NT, 2000 and XP.

schlenk I did check for NT and Win9x which don't interpret the first "" parameter to start as window title and W2k and up which do that and simply insert a dummy value if needed.Its braindead but documented in the help file of the start command...


See also: Tcl 9.0 WishList - #66.


AM kroc informed me about yet another utility that is available for this type of things: [L1 ]. Typical usage:

 [catch [ list exec printraw.exe [file nativename [file join $dir spoolout *.prn]] $printername ]]

KPV But the whole point of the above exercise was to ask the Windows OS how to print a text file. Theorectically it should work regardless of which utility is present or not.

AM I just (mis)used the page to document this utility - I could not find the other one. I quite appreciate this insight, as I have an immediate use for it!!

AM Can anyone shed light on the question how to achieve this on a Macintosh? (I do not have access to one, but I am interested to know how it would work there)

Lars H In Mac OS X there is a Unixy command enscript which can be used for this. Probably the traditional lp/lpr can be used as well (although these may in fact be using the enscript thing to do formatting and such). On Mac OS 9 you would probably have to do something along the lines above: starting "SimpleText" (or whatever it is called in English), tell it to open a new file, tell it to insert the text you want, and then tell it to print the thing; all via AppleEvents directly (e.g. using TclAE) or via Applescript (the Tclapplescript extension). If the text is already in a file it might however be easier to tell the Finder to print it, as that will then call upon the proper application to do the printing.


Also, check out http://sf.net/ project tclgdp which is a Tcl/Tk library and program to allow easy printing to the Nintendo Gameboy Printer from a PC.


[Peter Newman 21 March 2004: The simplest way to print a text file on Windows is to go:-

 type d:\path\to\myfile.txt > prn

from the DOS prompt. "Type" prints the specified file to stdout (by default). It's the DOS equivalent to Unix's CAT. The "> prn" re-directs output to the default printer.

So from Tcl:-

 exec $env(COMSPEC) /c type [file attribute d:\path\to\myfile.txt -shortname] > prn

should work on ALL versions of DOS and Windows. COMSPEC is an environment variable that I understand is available on all versions of Windows and points to the DOS shell (typically either COMMAND.COM or CMD.EXE). And we convert the file to 8.3 form so that it will work even on DOS systems that don't support long filenames.

Unfortunately, the above doesn't work. Exec complains:-

 Can't execute "c:\windows\command.com": no such file or directory.

But c:\windows\command.com (which is what $env(COMSPEC) evaluates to on my system) DOES exist. So either I've wired up the call to exec wrong - or exec has a bug in it. I couldn't be bothered trying to figure exec out (as you can see from all the ifs, but and maybes in the man page - and from the discussion above, that command obviously needs a LOT more work). Use winutils launch or shell instead, and it'll work.

The difference between the "notepad /p myfile.txt" and "type myfile.txt > prn" methods is that "type myfile.txt > prn" sends output directly to the printer in 10 CPI ASCII mode. It by-passes the Windows printer driver. So it's fast (printing starts immediately). But the font is quite large - so you waste lots of paper. The "notepad /p myfile.txt" method uses the Windows printer driver. So there's a 3 three year delay before printing starts - but the font used is usually smaller. Hence less wasted paper.


Category Printing