Strike Up the Bands

To have your program do its own banding, you first define a variable of type RECT:

RECT rect ;

You'll recall that the RECT structure has four fields named left, top, right, and bottom. For each page, you start by making an Escape call for the subfunction NEXTBAND, passing to it a pointer to rect. On return, rect contains the coordinates of the first band. The coordinates are always device coordinates (pixels) regardless of the current mapping mode of the printer device context. You make GDI calls to print in that band. You then call the NEXTBAND Escape function again to obtain the coordinates of the next band, and you print in that band. When the RECT structure passed to Escape is returned empty (all fields set to 0), the page is done.

Here's what the code looks like to print a single page. For simplicity's sake, this code doesn't take into account errors that can be returned from the Escape functions or checks of the bUserAbort value:

Escape (hdcPrn, NEXTBAND, 0, NULL, (LPSTR) &rect) ;

while (!IsRectEmpty (&rect))

{

[call GDI functions to print in band]

Escape (hdcPrn, NEXTBAND, 0, NULL, (LPSTR) &rect) ;

}

Each NEXTBAND Escape call except the first performs a function similar to the NEWFRAME Escape call: It signals to the GDI module and to the printer device driver that the entire band has been defined and that it can now be saved in a disk file (or written to the printer if the Print Manager is not loaded). You don't want to call the NEWFRAME Escape function after this loop has run its course. If you do so, you'll get a blank page between each printed page. Nor can you terminate the loop before receiving an empty rectangle and then make a NEWFRAME Escape call to skip the rest of the page. In short, you use either NEWFRAME to print a page without banding or multiple NEXTBAND calls to print a page with banding. Don't mix NEWFRAME and NEXTBAND Escape functions for the same page.

It's easiest to visualize banding for a dot-matrix printer. Before illustrating the process, we need to make a distinction between the ”top of the paper“ (which is always the section of the paper printed first) and the ”top of the page“ (which depends on whether the printer driver is in portrait or landscape mode).

In portrait mode, the top of the page is the same as the top of the paper. The bands go down the page. The rect.left value in the RECT structure set by the NEXTBAND Escape call is always 0, and rect.right is always equal to the width of the printing area in pixels (the value obtained from GetDeviceCaps with a HORZRES parameter). For the first band, rect.top equals 0. For each successive band, rect.top equals the rect.bottom value of the previous band. For the last band, rect.bottom equals the height of the printing area in pixels. (See Figure 15-11.)

Thus in each band, you can print from the rect.left and rect.top coordinates up to (but not including) the rect.right and rect.bottom coordinates. If you call the function:

Rectangle (hdcPrn, rect.left, rect.top, rect.right, rect.bottom) ;

the rectangle will be printed on the outermost edges of the band. (Recall that the right and bottom sides of the rectangle drawn by Rectangle are actually one pixel short of the points indicated by the last two parameters.)

In landscape mode, the dot-matrix printer must print the document sideways, starting from the left side of the page. The bands are in exactly the same area on the paper, but the rectangle coordinates are different, because the left side of the page is now the top of the paper. In landscape mode, rect.top is always 0, and rect.bottom is a constant equal to the height of the printing area in pixels (the value obtained from GetDeviceCaps using the VERTRES parameter). For the first band, rect.left equals 0. For the last band, rect.right is the width of the printing area in pixels. (See Figure 15-12 on the following page.)

A laser printer or a plotter might handle banding differently than a dot-matrix printer, because the printer output might not need to be sent to the printer sequentially from the top of the page to the bottom. Although Figures 15-11 and 15-12 represent the normal case, your program shouldn't assume that the banding rectangles will follow these patterns.

Separating your printer output into bands might seem like a major headache. But even if you use banding, you don't need to include a lot of banding logic. The band is a clipping region. You can make GDI calls that print outside the band, and Windows will ignore everything except what falls inside the band. This means that for each band, you can make all the GDI calls for the entire page.

You can determine whether a particular driver requires banding support by checking the RC_BANDING bit of the value returned from GetDeviceCaps using the RASTERCAPS parameter. As I mentioned before, this information is of concern only to GDI. Whether a driver requires banding support or not, the GDI module always supports the NEXTBAND Escape call. If the driver doesn't require banding support, the first NEXTBAND Escape call for a page returns a rectangle equal to the size of the printing area. The second NEXTBAND call for a page returns an empty rectangle.