|
Part 3: Dealing with Different Paper Sizes
Tidying Up Loose Ends
Before I get on to dealing with paper sizes, I just want to tidy up an issue
that arose in correspondance following last month's article.
Andrew Hosking emailed me saying he had tried out the code to control the duplex
setting and found that it just wouldn't work for him. We exchanged a few emails
before we discovered the cause. It was a limitation that I knew about, but had
neglected to mention in the article.
The code will work perfectly happily with a networked printer, but only if
the printer driver is installed on the local machine. If printing is relying
on the printer driver on the printer server, then the calls to the Windows API
do not work. The workaround is to install a copy of the appropriate printer
driver on the local machinepointing to the network printer.
If you are working in a corporate networked environment, you will probably
need the assistance and agreement of the system administrator for this (unless
you are the system administrator!)
Paper Sizes
So now to the main business. In Part 1 of this series, I dealt with selecting
paper trays, and pointed out that there are significant inconsistencies between
the way Word deals with them and the way Windows does. If you thought that was
a mess, you ain't seen nothin' yet! The handling of paper trays is a model of
logic and consistency compared to how Word deals with paper sizes.
Why Do We Need to Know About Paper Sizes in Code?
If you are in the US and have received a Word document from Europe, the document
is probably formatted A4, while your printer is set up for US Letter.
The larger types of laser printer are sometimes too clever for their own good.
On receiving a request to print an A4 document when they are set up for Letter,
they usually sit there flashing an "I need help" message on their
LCD display. In fact, all that is usually needed is to press the "Continue"
button on the printer and it will happily get on with the task. Because US Letter
is shorter and wider than A4, you might have a large right margin and lose a
bit of the page footer text on the printout.
One way to deal with this is to reformat documents so that they match the paper
size you actually have in the printer. That is the ideal, but it isn't always
practicable. The way in which Word documents are laid out varies a great deal
from person to person, and simply changing the paper size in the Page Setup
dialog can result in the most incredible mess, especially if manual page breaks
have been used to make sure that related information is all grouped on the same
page.
An alterative is to fool the printer into thinking that it has A4 paper when
it is actually loaded with Letter. Then the print job will go through uninterrupted.
You can do this manually by going to the Printer Properties dialog and changing
the paper size there. (Remember to change it back again afterwards!) If you
have a program that is printing a large batch of documents, you need to be able
to do the same thing in code.
In the Part 1 article on paper trays, there was no need to have Windows API
code to get and set the default paper tray in the printer, because Word already
has methods in the Options object to do that for you. Unfortunately, the same
cannot be said for getting and setting the current paper size. Therefore, we
need some routines that will communicate with the printer driver to do this.
The code below allows you to get and set the paper width and height. The values
returned are in points (1/72") for compatibility with Word's PageSetup
object, even though the printer driver itself returns the height and width in
units of a tenth of a millimeter. Paste the following code into the end of the
same module that you created for the Part 2 article. (A complete listing of
all the code for all three parts of the article is available from the TechTrax
Library, ready to be imported into your project.)
Public Function GetPaperHeight() As Single
'Windows API returns page height in 1/10ths of a millimeter.
'Value converted to points for compatibility
'with the PageHeight property GetPaperHeight = CSng(GetPrinterProperty(DM_PAPERLENGTH)) * 72 / 254 End Function
Public Sub SetPaperHeight(sngHeight As Single) Dim lHeight As Long
'Windows API sets page height in 1/10ths of a millimeter. 'Value converted from points for compatibility 'with the PageHeight property lHeight = CLng(sngHeight * 254 / 72) SetPrinterProperty DM_PAPERLENGTH, lHeight End Sub
Public Function GetPaperWidth() As Single 'Windows API returns paper width in 1/10ths of a millimeter. 'Value converted to points for compatibility 'with the PageWidth property GetPaperWidth = CSng(GetPrinterProperty(DM_PAPERWIDTH)) * 72 / 254 End Function
Public Sub SetPaperWidth(sngWidth As Single) Dim lWidth As Long
'Windows API sets page height in 1/10ths of a millimeter. 'Value converted from points for compatibility 'with the PageWidth property lWidth = CLng(sngWidth * 254 / 72) SetPrinterProperty DM_PAPERWIDTH, lWidth End Sub
Public Function GetPaperSize() As Long GetPaperSize = GetPrinterProperty(DM_PAPERSIZE) End Function
Public Sub SetPaperSize(iPaperSize As Long) SetPrinterProperty DM_PAPERSIZE, iPaperSize End Sub
The code above makes use of the SetPrinterProperty and GetPrinterProperty
routines that I listed in last month's Part 2 article.
Getting a List of Available Paper Sizes
The GetPaperSize and SetPaperSize routines listed above return
an ID number which represents a standard paper size. Of course, you need to
know what each code means.
It is possible to get a list of available paper size numbers and names using
code very similar to the code I described in Part 1 for getting paper trays.
The code is in fact so similar, that I am not going to list it here because
only a couple of lines would be different in each routine compared to the Part
1 code. Instead, the library file that goes with this article contains a complete
set of all the routines for all three parts of the article, with code duplication
eliminated by calling common routines.
Taking the same two printers that I mentioned in Part 1, here is a list of
the names and ID numbers for the paper sizes that they each support.
|
HP LaserJet 4/4Si MX PS
|
|
ID
|
Name
|
|
1
|
Letter
|
|
2
|
Letter Small
|
|
5
|
Legal
|
|
6
|
Statement
|
|
7
|
Executive
|
|
9
|
A4
|
|
10
|
A4 Small
|
|
11
|
A5
|
|
13
|
B5 (JIS)
|
|
14
|
Folio
|
|
15
|
Quarto
|
|
18
|
Note
|
|
19
|
Envelope # 9
|
|
20
|
Envelope # 10
|
|
21
|
Envelope # 11
|
|
22
|
Envelope # 12
|
|
23
|
Envelope # 14
|
|
27
|
Envelope DL
|
|
28
|
Envelope C5
|
|
31
|
Envelope C6
|
|
32
|
Envelope C65
|
|
34
|
Envelope B5
|
|
35
|
Envelope B6
|
|
36
|
Envelope
|
|
37
|
Envelope Monarch
|
|
38
|
6 3/4 Envelope
|
|
40
|
German Std Fanfold
|
|
41
|
German Legal Fanfold
|
|
43
|
Japanese Postcard
|
|
48
|
Reserved48
|
|
49
|
Reserved49
|
|
54
|
Letter Transverse
|
|
55
|
A4 Transverse
|
|
59
|
Letter Plus
|
|
60
|
A4 Plus
|
|
61
|
A5 Transverse
|
|
62
|
B5 (JIS) Transverse
|
|
64
|
A5 Extra
|
|
65
|
B5 (ISO) Extra
|
|
69
|
Japanese Double Postcard
|
|
70
|
A6
|
|
73
|
Japanese Envelope Chou # 3
|
|
74
|
Japanese Envelope Chou # 4
|
|
78
|
A5 Rotated
|
|
81
|
Japanese Postcard Rotated
|
|
82
|
Double Japan Postcard Rotated
|
|
83
|
A6 Rotated
|
|
87
|
Japan Envelope Chou # 4 Rotated
|
|
88
|
B6 (JIS)
|
|
89
|
B6 (JIS) Rotated
|
|
91
|
Japan Envelope You # 4
|
|
93
|
PRC 16K
|
|
94
|
PRC 32K
|
|
95
|
PRC 32K(Big)
|
|
96
|
PRC Envelope # 1
|
|
97
|
PRC Envelope # 2
|
|
98
|
PRC Envelope # 3
|
|
99
|
PRC Envelope # 4
|
|
100
|
PRC Envelope # 5
|
|
101
|
PRC Envelope # 6
|
|
102
|
PRC Envelope # 7
|
|
103
|
PRC Envelope # 8
|
|
107
|
PRC 32K Rotated
|
|
108
|
PRC 32K(Big) Rotated
|
|
109
|
PRC Envelope # 1 Rotated
|
|
110
|
PRC Envelope # 2 Rotated
|
|
111
|
PRC Envelope # 3 Rotated
|
|
112
|
PRC Envelope # 4 Rotated
|
|
119
|
Letter 8 1/2 x 11 in
|
|
120
|
Legal 8 1/2 x 14 in
|
|
121
|
A4 210 x 297 mm
|
|
122
|
Executive 7 1/4 x 10 1/2 in
|
|
123
|
Env Comm10 4 1/8 x 9 1/2 in
|
|
124
|
Env Monarch 3 7/8 x 7 1/2 in
|
|
125
|
Env DL 110 x 220 mm
|
|
|
Tektronix Phaser 850DP
|
|
ID
|
Name
|
|
1
|
Letter
|
|
7
|
Executive
|
|
9
|
A4
|
|
11
|
A5
|
|
126
|
# 10 Envelope
|
|
127
|
Monarch Envelope
|
|
128
|
# 6 3/4 Envelope
|
|
129
|
DL Envelope
|
|
130
|
C5 Envelope
|
|
131
|
Choukei 3 Envelope
|
|
132
|
Choukei 4 Envelope
|
|
Looking at these codes and similar lists for other printers, there is some
good news, some not-quite-so-good news and some really, really bad news.
First the good news. The lower-numbered codes (up to 41) and their associated
names are common between all the printers. Therefore, Letter paper uses code
1 and has the name "Letter" for any printer that supports it.
The not-quite-so-good news is that above code 41, there are lots of custom
paper sizes, and the codes, names and paper sizes vary between printers. Some
printers support custom sizes, and some don't. For those that support custom
sizes, there is no way of knowing from the name and number what that size actually
is. To find out, it would be necessary to set that size using the SetPaperSize
routine, and then find out the actual page height and width using the GetPaperHeight
and GetPaperWidth functions.
The really bad news is that the standard code numbers up to 41 don't align
with the values of the wdPaperSize constants used to set the PaperSize property
of Word's PageSetup object. Arrgghh!
The following table shows how Word's standard constants and the Windows API
code values map onto each other.
|
Paper Size
|
Win API Value
|
Word Constant Name
|
Constant Value
|
|
Letter
|
1
|
wdPaperLetter
|
2
|
|
Letter Small
|
2
|
wdPaperLetterSmall
|
3
|
|
Tabloid
|
3
|
wdPaperTabloid
|
23
|
|
Ledger
|
4
|
wdPaperLedger
|
19
|
|
Legal
|
5
|
wdPaperLegal
|
4
|
|
Statement
|
6
|
wdPaperStatement
|
22
|
|
Executive
|
7
|
wdPaperExecutive
|
5
|
|
A3
|
8
|
wdPaperA3
|
6
|
|
A4
|
9
|
wdPaperA4
|
7
|
|
A4 Small
|
10
|
wdPaperA4Small
|
8
|
|
A5
|
11
|
wdPaperA5
|
9
|
|
B4
|
12
|
wdPaperB4
|
10
|
|
B5
|
13
|
wdPaperB5
|
11
|
|
Folio
|
14
|
wdPaperFolio
|
18
|
|
Quarto
|
15
|
wdPaperQuarto
|
21
|
|
10 x 14 in
|
16
|
wdPaper10x14
|
0
|
|
11 x 17 in
|
17
|
wdPaper11x17
|
1
|
|
Note
|
18
|
wdPaperNote
|
20
|
|
Envelope # 9
|
19
|
wdPaperEnvelope9
|
24
|
|
Envelope # 10
|
20
|
wdPaperEnvelope10
|
25
|
|
Envelope # 11
|
21
|
wdPaperEnvelope11
|
26
|
|
Envelope # 12
|
22
|
wdPaperEnvelope12
|
27
|
|
Envelope # 14
|
23
|
wdPaperEnvelope14
|
28
|
|
C size sheet
|
24
|
wdPaperCSheet
|
12
|
|
D size sheet
|
25
|
wdPaperDSheet
|
13
|
|
E size sheet
|
26
|
wdPaperESheet
|
14
|
|
Envelope DL
|
27
|
wdPaperEnvelopeDL
|
37
|
|
Envelope C5
|
28
|
wdPaperEnvelopeC5
|
34
|
|
Envelope C3
|
29
|
wdPaperEnvelopeC3
|
32
|
|
Envelope C4
|
30
|
wdPaperEnvelopeC4
|
33
|
|
Envelope C6
|
31
|
wdPaperEnvelopeC6
|
35
|
|
Envelope C65
|
32
|
wdPaperEnvelopeC65
|
36
|
|
Envelope B4
|
33
|
wdPaperEnvelopeB4
|
29
|
|
Envelope B5
|
34
|
wdPaperEnvelopeB5
|
30
|
|
Envelope B6
|
35
|
wdPaperEnvelopeB6
|
31
|
|
Envelope
|
36
|
wdPaperEnvelopeItaly
|
38
|
|
Envelope Monarch
|
37
|
wdPaperEnvelopeMonarch
|
39
|
|
6 3/4 Envelope
|
38
|
wdPaperEnvelopePersonal
|
40
|
|
U.S. Standard Fanfold
|
39
|
wdPaperFanfoldUS
|
17
|
|
German Standard Fanfold
|
40
|
wdPaperFanfoldStdGerman
|
16
|
|
German Legal Fanfold
|
41
|
wdPaperFanfoldLegalGerman
|
15
|
|
User-defined
|
256
|
wdPaperCustom
|
41
|
Quite frankly, this is a horrid mess, and I cannot imagine why Microsoft chose
to implement a set of paper size codes in Word that is different from those
already standardised for use in Windows.
Still, we have to make the best of it we can. You can set the paper size for
the printer by setting the PaperSize property to one of the supported codes.
Generally, it is a good idea to make sure that the PaperSize of the printer
is equivalent to the PaperSize property of the PageSetup object. For instance,
if the ActiveDocument.PageSetup.PaperSize is wdPaperLetter, the you would have
to ensure that you use the SetPaperSize subroutine to set the printer's current
paper size to 1, and quietly forget about the fact that the value for wdPaperLetter
is actually 2! A routine that will check whether a document is A4 size and set
the page size accordingly is given below.
Public Sub CheckA4BeforePrinting() Dim iCurrentPaperSize As Long
If ActiveDocument.PageSetup.PaperSize = wdPaperA4 Then
'Save current paper size so it can be restored afterwards iCurrentPageSize = GetPaperSize
'Set printer to A4 (value 9 in Win API codes) and print SetPaperSize 9 ActiveDocument.PrintOut Background:=False
'Restore the original paper size SetPaperSize iCurrentPaperSize
Else
'No need for special action, just print ActiveDocument.PrintOut Background:=False
End If End Sub
Library Code
I have provided a module which can be imported directly into your Word VBA project
which includes all the routines described in all three parts of this article.
Click here to download it.
|