How to Print Entire VB Form and Control the Printed Size

ID Number: Q84066

1.00

WINDOWS

Summary:

The Visual Basic PrintForm method provides a way to print the client

area of a form. However, PrintForm does not allow you to control the

size or proportion of the printed output, or to print the non-client

area (the caption and border) of the form.

The following code example uses Windows API functions to print the

entire form, and provides a method to control the size of the output.

This method can also be used to print only the client area to a

specific size and to control the position of the printed form to allow

text or other graphics to be printed on the same page as the image of

the form. The method is also applicable to printing all the forms in a

project.

This information applies to the Microsoft Visual Basic programming

system version 1.0 for Windows.

More Information:

Combining the Windows API functions BitBlt, StretchBlt,

CreateCompatibleDC, DeleteDC, SelectObject, and Escape allows greater

control over the placement and size of the printed form than the

PrintForm method. In a two-part process, the image of the entire form

is captured by using BitBlt to make an invisible picture, and is

turned into a persistent bitmap using the AutoRedraw property. Then

the picture is printed using the method of printing a picture control

(outlined in a separate article, found by querying for the following

word in the Microsoft Knowledge Base):

CreateCompatibleDC

This method works on maximized forms as well as any smaller forms.

The use of GetSystemMetrics allows a general procedure to handle

different window border styles passed to it by querying the video

driver for the size of windows standard borders in pixels.

The example below requires a single form with an invisible picture

control.

Example

-------

1. Add the following code to the general Declarations level of the

form in a new project:

Note: All Declare statements below must be on one line each.

DefInt A-Z

Declare Function BitBlt Lib "gdi" (ByVal hDestDC, ByVal X, ByVal Y,

ByVal nWidth, ByVal nHeight, ByVal hSrcDC, ByVal XSrc,

ByVal YSrc, ByVal dwRop&)

Declare Function CreateCompatibleDC Lib "GDI" (ByVal hDC)

Declare Function SelectObject Lib "GDI" (ByVal hDC, ByVal hObject)

Declare Function StretchBlt Lib "GDI" (ByVal hDC, ByVal X, ByVal Y,

ByVal nWidth, ByVal nHght, ByVal hSrcDC, ByVal XSrc,

ByVal YSrc, ByVal nSrcWidth, ByVal nSrcHeight, ByVal dwRop&)

Declare Function DeleteDC Lib "GDI" (ByVal hDC)

Declare Function Escape Lib "GDI" (ByVal hDC, ByVal nEscape,

ByVal nCount, lplnData As Any, lpOutData As Any)

Declare Function GetSystemMetrics Lib "User" (ByVal nIndex)

Const SM_CYCAPTION = 4

Const SM_CXBORDER = 5

Const SM_CYBORDER = 6

Const SM_CXDLGFRAME = 7

Const SM_CYDLGFRAME = 8

Const SM_CXFRAME = 32

Const SM_CYFRAME = 33

Const TWIPS = 1

Const PIXEL = 3

Const NULL = 0&

Const SRCCOPY = &HCC0020

Const NEWFRAME = 1

Dim ModeRatio, XOffset, YOffset As Integer

2. Set the following properties at design time:

Control Property Setting

------- -------- -------

Form1 FormName Form1 (default)

Form1.Picture1 CtlName Picture1 (default)

Form1.Picture2 CtlName Picture2 (default)

Form1.File1 CtlName File1 (default)

You can add any other control(s) to the form to print. If a picture

control is drawn at run time, be sure to set its AutoRedraw property

to True so that the graphics will be transferred by the Windows API

call BitBlt and eventually printed by StretchBlt.

3. Add the following code to the Form_Load procedure of Form1:

Sub Form_Load ()

' Size the form explicitly to match parameters of StretchBlt

' Or use design time size to set coordinates

Form1.Move 1095, 1200, 8070, 5280

' Size two example controls

File1.Move 4080, 120, 2775, 2535

Picture1.Move 240, 120, 2775, 2535

' Put up a caption to indicate how to print the form

Form1.Caption = "Double Click to Print Form And Text"

'The following *optional* code illustrates creating a persistent

'bitmap that will successfully StretchBlt to the printer

Picture1.AutoRedraw = -1 'Create persistent bitmap of picture

'contents

Picture1.Line (0, 0)-(Picture1.ScaleWidth / 2,

Picture1.ScaleHeight / 2), , BF

Picture1.AutoRedraw = 0 'Toggle off

'Make sure the temporary workspace picture is invisible

Picture2.visible = 0

End Sub

4. Add the following code to the general procedure level of the form:

Sub FormPrint (localname As Form)

' display cross

screen.MousePointer = 2

' calculate ratio between ScaleMode twips and ScaleMode pixel

localname.ScaleMode = PIXEL

ModeRatio = localname.height \ localname.ScaleHeight

localname.ScaleMode = TWIPS

XOffset = (localname.width - localname.ScaleWidth) \ ModeRatio

YOffset = (localname.height - localname.ScaleHeight) \ ModeRatio

CapSize% = GetSystemMetrics(SM_CYCAPTION) 'The height of the caption

'The size of fixed single border:

FudgeFactor% = GetSystemMetrics(SM_CYBORDER)

' The fudgefactor is due to inevitable mapping errors when converting

' logical pixels to screen pixels. This example is coded for 640X480

' screen resolution. For 800X600, remove the fudgefactor.

' For other resolutions, tweak for perfection!

Select Case localname.BorderStyle

Case 0 ' None

XOffset = 0

YOffset = 0

Case 1 ' Fixed Single

XOffset = GetSystemMetrics(SM_CXBORDER)

YOffset = GetSystemMetrics(SM_CYBORDER) + CapSize% - FudgeFactor%

Case 2 ' Sizeable

XOffset = GetSystemMetrics(SM_CXFRAME)

YOffset = GetSystemMetrics(SM_CYFRAME) + CapSize% - FudgeFactor%

Case 3 ' Fixed Double

XOffset = GetSystemMetrics(SM_CXDLGFRAME) + FudgeFactor%

YOffset = GetSystemMetrics(SM_CYDLGFRAME) + CapSize%

End Select

'Size the picture to the size of the form's non-client (complete) area

Picture2.Move 0, 0, localname.Width, localname.Height

' Note that Bitblt requires coordinates in pixels.

Picture2.ScaleMode = PIXEL

' Clear Picture property of any previous BitBlt image

Picture2.Picture = LoadPicture("")

' -1 equals true: Must Have This!!!

Picture2.AutoRedraw = -1

' Assign information of the destination bitmap.

hDestDC% = Picture2.hDC

X% = 0: Y% = 0

nWidth% = Picture2.ScaleWidth

nHeight% = Picture2.ScaleHeight

' Assign information of the source bitmap.

' Source is entire client area of form (plus non-client area)

' XOffset and YOffset settings depend on the BorderStyle chosen for

' the form

hSrcDC% = localname.hDC

XSrc% = -XOffset: YSrc% = -YOffset

' Show transition to BitBlt by changing MousePointer

Screen.MousePointer = 4

' Assign the SRCCOPY constant to the Raster operation.

dwRop& = SRCCOPY

Suc% = BitBlt(hDestDC%, X%, Y%, nWidth%, nHeight%, hSrcDC%, XSrc%,

YSrc%, dwRop&) ' this must be placed on one line

' Start the StretchBlt process now.

' Assign persistent bitmap to Picture property:

Picture2.Picture = Picture2.Image

' StretchBlt requires pixel coordinates.

Picture2.ScaleMode = PIXEL

Printer.ScaleMode = PIXEL

'* The following is an example of mixing text with StretchBlt

Printer.Print "This is a test of adding text and bitmaps "

Printer.Print "This is a test of adding text and bitmaps "

Printer.Print "This is a test of adding text and bitmaps "

'* If no text is printed in this procedure

'* then you must add minimum: Printer.Print " "

'* to initialize Printer.hDC

' now display hour glass for the StretchBlt to printer

screen.MousePointer = 11

hMemoryDC% = CreateCompatibleDC(Picture2.hDC)

hOldBitMap% = SelectObject(hMemoryDC%, Picture2.Picture)

' You adjust the vertical stretch factor of the form in the

' argument "Printer.ScaleHeight - 1000":

ApiError% = StretchBlt(Printer.hDC, 0, 192,

Printer.ScaleWidth - 300, Printer.ScaleHeight - 1000,

hMemoryDC%, 0, 0, Picture2.ScaleWidth,

Picture2.ScaleHeight, SRCCOPY) ' concatenate above

' The second parameter above allows for text already printed: modify

' accordingly

hOldBitMap% = SelectObject(hMemoryDC%, hOldBitMap%)

ApiError% = DeleteDC(hMemoryDC%)

'* The following is an example of mixing text with StretchBlt

' Set the printer currentY to allow for the size of the StretchBlt

' image. (This is relative to size of form and stretch factors chosen)

Printer.currentY = 2392 'in Twips

Printer.Print "This is for text after the StretchBlt"

Printer.Print "This is for text after the StretchBlt"

Printer.Print "This is for text after the StretchBlt"

Printer.EndDoc

ApiError% = Escape(Printer.hDC, NEWFRAME, 0, NULL, NULL)

'reset MousePointer to default

Screen.MousePointer = 1

End Sub

5. Add the following code to the Double_Click event:

Sub Form_DblClick ()

FormPrint Form1

End Sub

6. After saving the project, run the example.

Double-click the form to invoke the FormPrint procedure. Any form

passed as a parameter to FormPrint will be printed. BitBlt will

transfer the image to the Picture control, then StretchBlt transfers

it to the printer DC, which will print the image that was transferred

by BitBlt.

Optionally, you could place text or graphics in the picture

(Form1.Picture2) before printing with StretchBlt or print directly

to the page using Printer.Print or Printer.Line. If you choose the

latter method, by adjusting the second and third parameters of

StretchBlt, you can make the already printed content be followed by

the image of the form on the same page.

Reference(s):

"Microsoft Windows Programmer's Reference Book and Online Resource"

(Add-on kit number 1-55615-413-5)

Additional reference words: 1.00