Updated 2016-02-19 06:01:23 by HJG

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: [1]. 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 is a bug-ridden disaster that needs a LOT more work). Use winutils launch or shell instead, and it'll work.

EKB It worked for me! Tcl 8.4.7.0 didn't complain about a nonexistent COMSPEC when I ran something like the above code.

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 year delay before printing starts - but the font used is usually smaller. Hence less wasted paper.

KPV On my Win2k with a local Canon printer this doesn't work--the command returns immediately but comes out on the printer. Also, I have my doubts on how this would work with a network printer.

Peter Newman 21 March 2004: Yeah! The point I was trying to make was that the STANDARD way to print a text file from DOS/Windows is to go:-
 type d:\path\to\myfile.txt > prn

from the DOS prompt.

I know that works on any version of DOS (from 2.00 upwards) and Windows 95/98 (because I've done it a million times). I ASSUME it'll also work on Windows 2000/NT and XP. But maybe not. Did you try typing the above from the DOS prompt?

It also works just fine with Perl's system command (on DOS and Windows 95/98). But it doesn't work with Tcl's exec. The problem is with exec (and/or the way we're calling it). Use winutils instead.

It should work with network printers too. But they have to be set up right. Usually PRN points to the DOS/Windows default printer. And LPT1 is a synonym for PRN. And LPT2 to LPT4 point to any other printers you may have. But you'll have to check your DOS/Windows documentation for the details - especially how configure them to point to your network printers. I've never myself tried this with network printers - though I'm sure it can be done.

KPV Sorry, I was unclear: the command fails for me even from the command prompt. Win95/98 are radically different than win2k and XP--they're really just a shell on top of command.com--so I'm NOT surprised it doesn't work.

Peter Newman: If in doubt, read the manual I went to the Microsoft web site and looked at the Win2000 manual. And sure enough it has a TYPE command. But that command DOESN'T support re-direction to printers. Instead, there's PRINT command for printing text files to printers. And that PRINT command supports both local and network printers.

So to summarise! To print a text file under DOS/Windows from the DOS prompt (and assuming that Win 2K, NT and XP all work the same):-
 type  d:\path\to\myfile.txt > prn      # DOS and Windows 9x
 print d:\path\to\myfile.txt            # Win 2K (and presumably also NT and XP)

And since anything you can do from the DOS prompt, you should also be able to do with exec, you should also be able to do those from Tcl.

Also, I don't think it's true that Win 2K, NT and XP are radically different from DOS and Win 9x. Win 2K, NT and XP support basically the same DOS commands as Win 9x. But there are some minor differences - as with TYPE/PRINT described above. And there are a whole load of new network/Internet related commands - to give the Win 2K, NT and XP command prompt a lot more Unix like power. KPV The difference between Win95/98 and WinNT/2K/XP is that the former uses DOS as it's underlying OS while the latter is a totally new OS written from scratch. Peter Newman Not as far as the DOS Prompt and printing text files is concerned. The Win 2K/NT/XP DOS Prompt is a straight-forward upgrade of the Win 9x/DOS DOS Prompt. The traditional DOS commands are all there - with exactly the same syntax (ok, maybe a few small differences) - and lots of enhancements.

Note also that:-

  1. Under DOS and Windows 9x you can also use:-
 COPY /b d:\path\to\myfile.txt prn

  1. The PRINT differs from TYPE and COPY is that it maintains a background print spooler. So it's slower.
  2. The printer support in TYPE and COPY (under DOS and Windows 9x) stems from the days where printers where connected to the PARALLEL port. Nowadays, most printers are USB or network connected. So even under DOS and Windows 9x, you won't be able to TYPE or COPY to a USB or network printer unless the OS concerned supports them.
  3. PRINT is also available under Windows 9x and DOS. I've got a DOS version 4.00 manual that lists it.
  4. Looking on the Internet I found references to the fact that Win 2K, NT and XP have a 15 second delay before printing starts - which fools some people into thinking nothing's happening. Apparently it can be fixed - and Microsoft have details on how to do this.

So to SUMMARISE (again)! To print a text file under DOS/Windows:-
 Go to your DOS Prompt Reference Manual and check out the:-

  • TYPE
  • COPY and;
  • PRINT
 commands. Then use whichever works (on your system).

But note that:-

  1. The alternative method of using "NOTEPAD /P" (discussed above), has the advantage of using smaller font sizes. So it usually looks better - and wastes less paper.
  2. COPY, TYPE and PRINT generally wrap long lines automatically. So they're usually the best solution for PROGRAM LISTINGS. NOTEPAD usually silently truncates long lines (which is irritating/dangerous with program listings).
  3. NOTEPAD (at least the Windows 95 versions of it,) can't handle Unix and Mac text files. It usually sees them as one long line. A major PITA. It may be the same with COPY, TYPE and PRINT. Whether the later versions of Windows are more Unix/Mac friendly I don't know. So you may have line ending translation issues to worry about too. (Note by PiPa, march 2007: load the .txt file in Word2000, add a space in any position, optionally delete that space, save the file as .txt - Done. All LF alone are converted in CRLF)
  4. Another Windows text file printing option to check, is winutils::shell winutils. This supports the "print" option - which looks to me like the Bill-Gates-approved method of printing things from Windows. :-(
  5. Another useful hack for printing text files under Windows, is to load them into your Web Browser, wrapped in <PRE>...your text file here...</PRE> tags. You should then be able to scale the font size down quite easily. And print it quite easily too. And most browsers support Unix and Mac line terminators too. The only problem is that long lines (if you have them,) will be truncated.

KPV Sorry, once again this doesn't work for me under Win2k. The print command is just a spooler for copying files to the parallel port and that just doesn't work. For a printing utility I maintain, I found that for network printers I had to open a socket to connect to it. I suspect my home printer doesn't understand straight ASCII but wants it own protocol (what you see when you say print to a file).

If the printer is on the network, and is an HP with the network card, it is possible to ftp a file to the printer for it to print. I'm currently using a strange printflow of using Openoffice to turn documents to pdf, and then Acrobat Reader to print the pdf to a Postscript file. Then, I ftp the Postscript file to the printer. Oi...

Peter Newman: OK, I see it's not working for you. But I didn't want users un-familiar with Windows to think that it's difficult or impossible to print text files from Windows. It isn't. It's a piece of cake, no matter which version you're using. You just use the TYPE, COPY and/or PRINT command(s) applicable to your version of Windows. And if the Windows version is network-aware, they'll print to both local and network printers too.

I know that's definitely true with DOS 2.00 to Windows 9x. And I just spent more time on the Microsoft web-site to check out 2K, NT and XP. They all support TYPE, COPY and PRINT - except perhaps NT - where PRINT may be missing and you use COPY instead. And all of 2K, NT and XP support both local and network printers.

As regards Windows 2K, see the "Print" command in the "Windows 2000 Command Reference" and "154498 - How to Print to Network Printer from MS-DOS-Based Programs" [2].

So if it doesn't work for you, the problem must be with your installation - not with Win 2K generally. But printer problems are hardly un-usual. If you haven't had those, you've never owned a printer. With 2K, NT and XP, I noticed a zillion articles on the Microsoft web site re. printer problems. If you'd like to upgrade to a decent bug-free O/S, I've got some old copies of MS-DOS 2.00. No network printing problems guaranteed (it doesn't support LANS)! Regards.

[JHJL]: I recently had similar command line printing problems on my Father's Win2K machine, viz using the the print command did not display an error but nothing was sent to the printer. I tried fiddling with copy to LPT1: etc to no avail. This was with an HP720 DeskJet. I installed an HP970CXi and then everything worked (print file.txt did just that). I can only conclude that the older HP720 driver is not as compatible with Win2k as the newer HP970CXi driver... With the newer printer installed, all of his old DOS based programs such as LocoScript, printed without problems.

RS 2006-03-17: Here's how I print utf-8 from a text widget via a temp file using notepad:
 proc print w {
    if {$::tcl_platform(platform) ne "windows"} {
        error "printing is only supported under Windows"
    }
    set filename c:/temp/[file tail [wm title .]]
    set f [open $filename w]
    fconfigure $f -encoding utf-8
    puts $f \ufeff[$w get 1.0 end]
    close $f
    exec cmd /c start /min notepad /p $filename
    file delete $filename
 }

Having \ufeff as first character instructs Notepad to read the file as UTF-8. The characters you want to print (Cyrillic in my case) have to be in the standard font, of course.

RJM All of the methods using windows executables lack the capability of selecting the printer via the standard dialog, as is possible with Schwarz' printer package. However, the latter does not support utf-8.

MHo I think under w2k and above, the PRN device does not exists. With w2k, there was some way to attach a devicename like LPT1: or PRN to a windows printer, but I don't recall the exact way and cannot find such option on my WinXP-PC right now... Such a device, if ever, only exists when using the 16bit environment with the old MSDOS command.com interpreter or MSDOS programs. Accessing PRN or LPT1: via redirection in my WinXP cmd.exe hangs the session.

Another way to use the printer is to share it. Afterwords it is possible to do the following:
 dir >> \\computername\sharename

even if the printer is on your own pc (named computername) (Unfortunally, the syntax \\.\ (= local PC) does not seem to work in this context). It is then also possible to print from within tcl:
 (bin) 49 % set p [open //win2000/drucker w]
 filef08818
 (bin) 50 % puts $p "Testprint"
 (bin) 51 % close $p

Kurt Schultz 2007-11-13

On many versions of Windows, you can copy files directly to a local, network, or shared printer.
 For example: COPY MyFile1.txt \\computername\sharename
 computername is your local PC name or network server name
 sharename is the printer name on your PC or network printer share name.

You can redirect the LPT ports to a network or shared printer using the following:
 NET USE LPT1 \\computername\sharename

Then you can copy or PRINT files to LPT1 or redirect output like DIR > LPT1

[parag] - 2014-03-25 04:52:35

Thanks a lot for your post..this is really helpful.. I am trying to print a text file using TYPE filename >prn then it does not work on USB printer because output of PRN command goes to LPT1 port directly. I can't install the loopback adapter or network adapter. Hence, I am not able to print on USB printers using TYPE/COPY/PRINT command.

I have also tried to use Start /min notepad /p <filename> command. This worked for me. However, the font is smaller and also margin is introduced in the printed output.I suppose, this has happened because it has gone through WINDOW driver of the printer.

However, this margin is distorting my printing job. Hence, i want to get the same printing output as I get when I print using TYPE/COPY/PRINT command. How can I by pass the windows driver introduced formatting of printing job using START /min notepad /p <filename> command?

It would be very helpful if some of you can reply..Thanks in advance..

RLE (2014-03-25): Your USB printer is likely LPT2 or LPT3 rather than LPT1. So try "type file > LPT2" or "type file > LPT3". (keep incrementing the number until you 1) find the printer 2) exhaust LPT9.

HJG 2016-02-14: See EasyTextPrint for an utility to convert plain textfiles to html-files for printing in the webbrowser.