Monday, June 9, 2008

Using a script to add a Windows printer form

A client of mine uses a custom paper size for plotting architectural proofs. The plotters themselves support the paper size, but the client also needs to plot to that size when creating a PDF. Since PDF printers are local devices, they needed to add the form to each workstation.

Since there seems to be very little on the net regarding how to manipulate printer forms, here's how:



1. Download and install the Windows 2003 Resource Kit Tools.

2. Distribute prnadmin.dll from the kit. The default location is C:\Program Files\Windows Resource Kits\Tools. I set up the network logon script to copy the file to C:\bin on each workstation.

3. Install the font. I used the following logon script (forgive the mangled formatting).

'----------------------------
' InstallForm15x21.vbs
' by Craig Putnam
' 20080609
' Installs a custom 15x21 printer form on workstations.
' This script requires prnadmin.dll to be present in the netlogon bin folder.
'----------------------------

option explicit

const FORM_NAME = "15x21"
const FORM_HEIGHT = 21
const FORM_WIDTH = 15

const INCHES = 25400

dim shell : set shell = createObject("Wscript.Shell")
dim master : set master = quietCreateObject("PrintMaster.PrintMaster.1")
if master is nothing then
runProgram("regsvr32 /s c:\bin\prnadmin.dll")
set master = createObject("PrintMaster.PrintMaster.1")
end if

if not formExists(FORM_NAME) then
createForm FORM_NAME, FORM_HEIGHT, FORM_WIDTH, INCHES
end if

'----------------------------
' Creates a printer form on this computer.
'
' Inputs: name: string: The name of the form.
' width: The width of the form.
' height: The height of the form.
' unit: The unit conversion factor. The base unit for form size is
' microns (1/1,000,000 of a meter).
'----------------------------
sub createForm(name,width,height,unit)
dim heightInMicrons, widthInMicrons
heightInMicrons = height * unit
widthInMicrons = width * unit
dim form : set form = createObject("Form.Form.1")
form.name = name
form.setSize heightInMicrons, widthInMicrons
form.setImageableArea 0, 0, heightInMicrons, widthInMicrons
master.formAdd form
set form = nothing
end sub

'----------------------------
' Determines whether a printer form of the given name exists on this computer.
'
' Inputs: name: string: The name of the form.
' Returns: boolean: Whether a form of the give name exists on this computer.
'----------------------------
function formExists(name)
dim form
for each form in master.forms
if form.name = name then
formExists = true
exit function
end if
next
formExists = false
end function

'----------------------------
' Creates an object without generating an error if creation fails.
'
' Inputs: name: string: The name of the object.
' Returns: The object, or the nothing value if creation fails.
'----------------------------
function quietCreateObject(name)
on error resume next

set quietCreateObject = createObject(name)
if err <> 0 then
err.clear
set quietCreateObject = nothing
end if
end function

'----------------------------
' Runs the given program. Directs all output to the log file. Note that if
' the program requires input from stdin, it will hang.
'
' Inputs: program: string: The program to run. This must be an executable
' that Windows can natively execute.
'----------------------------
function runProgram(program)
on error resume next

dim process : set process = shell.exec(program)
while process.status = 0
wscript.echo process.stdout.readAll
wscript.echo process.stderr.readAll
wscript.sleep 2
wend
wscript.echo process.stdout.readAll
wscript.echo process.stderr.readAll

set process = null
end function

'--------
' End of script InstallForm15x21.vbs
'--------

If you want to use the script-as is, replace FORM_NAME, FORM_WIDTH, and FORM_HEIGHT with the appropriate values. Windows measures forms in millionths of a meter, thus the inches conversion factor. If you want to customize the script, the resource kit includes decent documentation in prnadmin.doc.