Printing Documents in WSH

Printing documents is a fairly common automation task. Perhaps you want to batch print a folder full of documents, or maybe you’d like to automate report printing. In any case, WSH doesn’t necessarily provide a straightforward method for doing this. Let’s look at some different ways of printing documents in WSH.

Contributed by
Rating: 5 stars5 stars5 stars5 stars5 stars / 3
July 07, 2008
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

The majority of methods that we’ll be using to print will rely on the system’s default printer setting.  In order to change printers, you’ll need to be able to detect and set this system setting.  There are a number of ways to do this as you will see shortly.

First, let’s take a look at how WMI can be used to view information about installed printers.

strComputer = "."

Set objWMIService = GetObject("winmgmts:" _

   & "{impersonationLevel=impersonate}!" & strComputer _

       & "rootcimv2")

We’ll begin by connecting to the local WMI service at the rootcimv2 namespace.  This type of connection should look pretty familiar to you if you’ve used WMI at all in the past.

Set colInstalledPrinters = objWMIService.ExecQuery( _

   "Select * from Win32_Printer")

Next, we execute a query that polls all instances of the Win32_Printer class.  This class returns a collection object containing a reference to each installed printer.

For Each objPrinter In colInstalledPrinters

   WScript.Echo objPrinter.Name

Next

Now we’re able to use a simple For…Next loop to iterate through the collection of installed printers and print the name.  “Why is this important?” You ask.  It gives you a chance to see the naming conventions that you’ll be using throughout the rest of this article.

Determining the System Default Printer

The system default printer setting is stored in the local hardware profile in the Windows registry.  This is a global setting that is used by any application that relies on system APIs for printing.  Since this setting is stored in the registry, it becomes the first logical place to look for the current setting.

Set WshShell = CreateObject("WScript.Shell")

strRegVal = "HKCUSoftwareMicrosoftWindows NTCurrentVersionWindowsDevice"

 

strDefault = WshShell.RegRead(strRegVal)

strDefault = Left(strDefault, InStr(strDefault, ",") - 1)

You can use any method you like to read the required registry key.  For simplicity, I’ve used the WshShell object to read the registry, but I could have just as easily used WMI.  The key should contain something like the following:

Lexmark 3500-4500 Series,winspool,Ne04:

As you can see, the printer name is the first of a series of comma-delimited values.  Making use of VBScript’s InStr and Left functions allows us to parse out only the required information.

Once you have the printer name, you can construct a UNC path to the printer in the form of computernameprintername.  The WshNetwork object can be used to retrieve the local computer name.

The next method for retrieving the system default printer setting relies on WMI.

strComputer = "."

Set objWMIService = GetObject("winmgmts:" & strComputer _

   & "rootcimv2")

Set colPrinters = objWMIService.ExecQuery(_

   "Select * From Win32_Printer Where Default = '-1'")

After connecting to the local WMI service’s rootcimv2 namespace, we query the Win32_Printer class for all instances where the Default property is set to -1.  Keep in mind that -1 is the integer representation of a Boolean true value.  This query returns a collection of printer objects that have the Default value set to True.

For Each objPrinter In colPrinters

   strDevice = objPrinter.DeviceID

   strSystem = objPrinter.SystemName

Next

Next we’ll use a For…Next loop to iterate through the collection and read the DeviceID and SystemName properties for each printer object.  This may seem a bit redundant since there can only be one default printer, meaning that the colPrinters collection should only contain a single reference.  This is a valid argument, so if you prefer you can use this code instead.

strDevice = colPrinters.Item(0).DeviceID

strSystem = colPrinters.Item(0).SystemName

My only argument against this more direct method is that it will cause an error if it is run on a system that does not have any installed printers.  In that case, the colPrinters collection will not have any members and an error will be raised when trying to access a non-existent item.

Whichever method you choose to use, you will end up with the same result.  The DeviceID property will return the name of the printer and the SystemName property will return the name of the system that the device is installed on—the current computer name.

If Not IsEmpty(strDevice) Or Not IsEmpty(strSystem) Then

   strUNC = "" & strSystem & "" & strDevice

Else

   strUNC = ""

End If

Building a valid UNC path is as simple as concatenating our two variables with the proper forward slashes.  I’ve chosen to do this inside of an If block to again avoid errors in the scenario mentioned previously.

Setting the System Default Printer

Now we’ll take a look at ways of setting the system default printer setting.  This will allow us to control what printer to use in cases when we cannot specify one directly.

Set WshNetwork = CreateObject("WScript.Network")

WshNetwork.SetDefaultPrinter(strPrinter)

The simplest method of setting the default printer relies on the SetDefaultPrinter method of the WshNetwork object.  It accepts a single parameter which is a valid UNC path to the printer to be used.

The next method uses WMI to set the default printer and is almost exactly the opposite of the script we used to determine the current system setting.

strComputer = "."

Set objWMIService = GetObject("winmgmts:" & strComputer _

   & "rootcimv2")

 

Set colInstalledPrinters =  objWMIService.ExecQuery _

   ("Select * from Win32_Printer Where Name = '" & strPrinter & "'")

In this case, we’re querying the Win32_Printer class for a specific printer.  The strPrinter variable should contain the name of an installed printer exactly as it is listed by the sample script at the beginning of this article.

Printer names are defined by their drivers.  The driver name is taken from the .inf file used to install the driver.  You can see this name in the Printers and Faxes Control Panel applet or in Device Manager with “Show hidden devices” enabled.

This WMI query will return a collection of printer objects that should again only have a single member unless there are multiple instances of the same printer installed.

For Each objPrinter In colInstalledPrinters

   objPrinter.SetDefaultPrinter

Next

The printer object then provides the SetDefaultPrinter method, for a quick way of changing its Default property to True.

You can also set the system default printer by using the system API with the help of rundll32 on the command line.

Set WshShell = CreateObject("WScript.Shell")

strCommand = "rundll32 printui.dll,PrintUIEntry /y /n" & strPrinterUNC

result = WshShell.Exec(strCommand)

This method uses the WshShell object’s Exec method to run the appropriate command line.  The strPrinterUNC variable should contain a fully qualified UNC path to an installed printer.

Regardless of whichever method you choose to use, any time you set a printer as the default, any other installed printers will automatically have their default value set to False.

One final method of setting the default system printer would be to manually write the registry key that you saw previously.  I’m not providing an example of this since it’s best to avoid writing directly to the registry from an unattended script whenever possible.

Shell Printing and Printing with Notepad

Now that we have a method of controlling output print devices, let’s take a look at how to send a print job.  The first method uses the Windows Shell.  If you open Explorer or My Computer and right-click a file in a common document format, you should see a Print entry on the context menu. This provides a quick method of printing the document without having to first open the host application.

Set objShell = CreateObject("Shell.Application")

Set objFolder = objShell.NameSpace(strFolder)

Set colItems = objFolder.Items

 

For Each objItem In colItems

   If objItem = strFile Then

       objItem.InvokeVerb("Print")

       Exit For

   End If

Next

After connecting to the Explorer Shell object (Shell32.dll), use the NameSpace method to return a folder object for the folder where your file or files are located.  Next, you can use an If block nested inside of a For…Next loop to locate a specific file to print.

There is no way to specify a file directly without first connecting to its parent Folder object.  This is the only way to retrieve a File object for the specified file.

Finally, the InvokeVerb method is used to execute the Print command.  This is effectively the same as right-clicking a file and choosing Print from the context menu.  Note that this will cause an error if the selected file’s context menu does not have a Print entry.

While the Shell method above will work for most recognized file types, you may run across instances when it will not.  This is especially true if files have been renamed with unrecognized extensions.

The Shell Print method will print to the system default printer.

In these cases, you can print text-based files very easily using the Notepad application.  Notepad provides a simple command line that can be used to print a file to the default printer without having to open the application directly.

Set WshShell = CreateObject("WScript.Shell")

strCommand = "notepad /P " & Chr(34) & strFile & Chr(34)

result = WshShell.Exec(strCommand, 0, False)

Here again we return the WshShell object’s Exec method to execute our command line.  Notice that I’ve used Chr(34) to enclose the file path in double quotes in case it contains spaces.  The strFile variable may contain either an absolute or relative path to the file to be printed.

Printing Word and PDF Documents

There may still be a few instances where the Shell method and Notepad may not be enough for your printing needs.  In these cases, you can look to outside applications.  This may be especially true if you are trying to print a document in a proprietary format.

I’m going to show you very quickly how to automate two common applications for printing Microsoft Word and Adobe PDF documents.  Again, if your files use registered file extensions, even these should be printable using the Shell method.

Microsoft Word supports a very wide range of document formats and can be a very powerful tool for printing.  The Word OLE automation object also provides very thorough access to Word’s print capabilities, so printing with this method is both powerful and highly configurable.

Const wdDoNotSaveChanges = 0

 

Set objWord = CreateObject("Word.Application")

objWord.Visible = False

objWord.DisplayAlerts = False

Begin using Word by connecting to its OLE automation object.  I’m also setting its Visible property to False so that the application window is not visible, and its DisplayAlerts property to false to prevent displaying message boxes that require user input.

objWord.Documents.Open("mydoc.doc")

objWord.Options.PrintBackground = False

objWord.ActiveDocument.PrintOut

objWord.Application.Quit wdDoNotSaveChanges

From here, printing is pretty straightforward.  Use the Open method to open a document and then use the Document object’s PrintOut method to send it to the default printer.

Setting the PrintBackground property to False disables Word’s background printing feature and will prevent errors if the Word object is released before the print job completes.

It should be noted that the Word object’s print capabilities are much more powerful than you see here.  For a more in-depth look at printing with Microsoft Word, read my upcoming article “Advanced Word Object Scripting” here on ASP Free.

Now we’ll take a look at scripting Adobe Reader for printing PDF and other supported documents.

Set objAcroPDF = CreateObject("AcroPDF.PDF")

 

objAcroPDF.LoadFile(mypdf.pdf)

objAcroPDF.PrintAll

Set objAcroPDF = Nothing

Here we’re connecting to the AcroPDF object and using its LoadFile method to open a document.  Then a call to its PrintAll method sends the document to the default printer.

I don’t think the AcroPDF object was intended for use in scripting outside of Adobe’s own macros.  However, connecting to its COM object does expose methods to open and print documents.  I have not found an intrinsic method for closing the application, so be sure to set its object reference to Nothing after printing in order to release the object.

The AcroPDF object also exposes several other print methods that allow you to control print ranges and whether or not the document should be shrunk to fit pages.  It also provides a printWithDialog method that will display the Print dialog box and allow the user to select print settings.

objAcroPDF.printAllFit(blnShrinkToFit)

objAcroPDF.printPages(lngFrom, lngTo)

objAcroPDF.printPagesFit(lngFrom, lngTo, blnShrinkToFit)

objAcroPDF.printWithDialog

Printing Web Documents

The final method of printing with WSH that I’d like to show you is how to print from Internet Explorer.  There are a few distinct advantages to choosing this method.  The first is that it allows you to print any document supported by Internet Explorer, including web pages.  If you are connected to the Internet you can even supply a valid URL and print remote web pages.

The second advantage is a little different.  Until now, none of the methods I’ve shown you have provided a way to monitor when a print job actually completes; Internet Explorer provides an event that will allow you to do just that.

On the surface, printing in IE is going to seem a bit complicated, but if you take it slow and reread when necessary you should find it fairly easy to understand.

Const OLECMDID_PRINT = 6

Const OLECMDEXECOPT_DONTPROMPTUSER = 2

Const PRINT_WAITFORCOMPLETION = 2

Const OLECMDF_SUPPORTED = 1

Const OLECMDF_ENABLED = 2

 

blnPrintingComplete = False

Here we begin by declaring a few necessary constants and creating a Boolean value that we will use to determine when the print job has completed.  It should initially be set to False since the print job has not been created.

Set objIE = WScript.CreateObject("InternetExplorer.Application", "IE_")

Now we connect to the Internet Explorer object.  There are two things that you should take note of here.  First, notice that I’m explicitly using the WScript object’s CreateObject method as opposed to VBScript’s that we use when we don’t specify.  This brings us to the second noteworthy part.  The WScript object’s CreateObject method allows us to specify a second parameter that is to be used as a prefix for the object.  This is the prefix we will need later in order to make use of Internet Explorers events.

objIE.Visible = False

objIE.Navigate strFile

Next, I’m setting IE’s visible property to False to make sure that it doesn’t display visibly, and then I’m telling it to navigate to a document.  The variable strfile can be either a local file path or any valid URL.

Do While objIE.ReadyState <> 4

   WScript.Sleep 10

Loop

This next piece of code uses a Do…Loop to essentially pause script execution until the page has fully loaded.

If objIE.QueryStatusWB(OLECMDID_PRINT) = OLECMDF_SUPPORTED _

       + OLECMDF_ENABLED Then

   objIE.ExecWB OLECMDID_PRINT, OLECMDEXECOPT_DONTPROMPTUSER, _

       PRINT_WAITFORCOMPLETION, 0

   Do While Not blnPrintingComplete

       WScript.Sleep 50

   Loop

End If

 

objIE.Quit

This If block basically determines whether or not printing is supported before attempting to issue a print command using the ExecWB method.  The additional parameters instruct IE to print the current document, suppress any print dialog boxes, and wait for completion before continuing, respectively.

Printing Web Documents continued

You’ll notice that the Internet Explorer object is instructed to quit immediately after the If block.  To prevent IE from exiting prematurely, we insert a Do…Loop that monitors the Boolean value we created earlier in order to know when our print job has completed.

That being said, how do we know when the print job has completed?

Whenever a print job is sent to a printer, the system creates a “print template” that describes how the printed document should look.  Once the print job is completed, this template is then discarded.

As I said earlier, Internet Explorer provides an event that can be used to determine when a print job is completed.  This event actually monitors the destruction of the print template.  Since this doesn’t happen until a job is finished printing, it effectively lets us monitor when a print job has completed.

Sub IE_PrintTemplateTeardown(pDisp)

   WScript.Sleep 200

   blnPrintingComplete = True

End Sub

In order to do this you will need to place a subroutine at the end of your script.  Your subroutine uses a naming convention that VBScript recognizes as an event handle.  Notice that the subroutine name begins with the prefix we specified earlier, then an underscore, and finally the name of the event we want to monitor—in this case PrintTemplateTeardown.

Notice that I’ve also include a parameter in my declaration.  This is what our script is going to receive as input whenever this event fires.

The contents of the subroutine are fairly simple.  We pause script execution briefly to ensure that the print template has had time to be destroyed, and then we set our Boolean value to True to indicate that printing has completed.

Any time that the PrintTemplateTeardown event is fired, the code inside this subroutine will be executed.  Since VBScript events are handled asynchronously, this will continue to happen while the script continues to execute regularly.  This is why we created the loop earlier that monitors our Boolean value.  The script will continue to loop indefinitely until that value is changed when this event fires.

You now have several different ways of printing documents in WSH.  Feel free to use whatever method you choose depending on your software availability and document type.  Whatever you choose, remember to have fun with it.  Until next time, keep coding!

blog comments powered by Disqus
WINDOWS SCRIPTING ARTICLES

- More Windows Scripting Workarounds from Nilpo
- Overloading Methods and More in VBScript
- Improving MFC for Windows Vista
- Regular Expressions in VBScript
- Working with Dates in WMI
- Completing Calendars with VBScript Date Func...
- Building Calendars with VBScript Date Functi...
- Working With Dates and Times in VBScript
- Designing WCF DataContract Classes Using the...
- Understanding Dates and Times in VBScript
- Working With Arrays in VBScript
- Compressed Folders in WSH
- Using .NET Interops in VBScript
- Nilpo`s Scripting Secrets, Vol I
- Database operations using Silverlight 2.0 WC...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 11 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials