The FORMFEED Program

Our first printing program does nothing but cause a printer formfeed to eject the page. The FORMFEED program, shown in Figure 15-4, demonstrates the absolute minimum requirements for printing.

FORMFEED.MAK

#------------------------

# FORMFEED.MAK make file

#------------------------

formfeed.exe: formfeed.obj formfeed.def

link formfeed, /align:16, NUL, /nod slibcew libw, formfeed

rc formfeed.exe

formfeed.obj: formfeed.c

cl -c -Gsw -Ow -W2 -Zp formfeed.c

FORMFEED.C

/*---------------------------------------------

FORMFEED.C -- Advances printer to next page

(c) Charles Petzold, 1990

---------------------------------------------*/

#include <windows.h>

#include <string.h>

HDC GetPrinterDC (void) ;

int PASCAL WinMain (HANDLE hInstance, HANDLE hPrevInstance,

LPSTR lpszCmdLine, int nCmdShow)

{

static char szMsg [] = "FormFeed" ;

HDC hdcPrint ;

if (hdcPrint = GetPrinterDC ())

{

if (Escape (hdcPrint, STARTDOC, sizeof szMsg - 1, szMsg, NULL) > 0)

if (Escape (hdcPrint, NEWFRAME, 0, NULL, NULL) > 0)

Escape (hdcPrint, ENDDOC, 0, NULL, NULL) ;

DeleteDC (hdcPrint) ;

}

return FALSE ;

}

HDC GetPrinterDC (void)

{

static char szPrinter [80] ;

char *szDevice, *szDriver, *szOutput ;

GetProfileString ("windows", "device", ",,,", szPrinter, 80) ;

if ((szDevice = strtok (szPrinter, "," )) &&

(szDriver = strtok (NULL, ", ")) &&

(szOutput = strtok (NULL, ", ")))

return CreateDC (szDriver, szDevice, szOutput, NULL) ;

return 0 ;

}

FORMFEED.DEF

;-------------------------------------

; FORMFEED.DEF module definition file

;-------------------------------------

NAME FORMFEED

DESCRIPTION 'Printer Form Feed Program (c) Charles Petzold, 1990'

EXETYPE WINDOWS

STUB 'WINSTUB.EXE'

CODE PRELOAD MOVEABLE DISCARDABLE

DATA PRELOAD MOVEABLE MULTIPLE

HEAPSIZE 1024

STACKSIZE 8192

FORMFEED includes the GetPrinterDC function shown earlier. Other than obtaining the printer device context (and later deleting it), the program makes only three Escape calls. The first uses the STARTDOC subfunction to start a new document. It tests the return value from Escape and proceeds only if the value is positive:

if (Escape (hdcPrint, STARTDOC, sizeof szMsg - 1, szMsg, NULL) > 0)

The fourth parameter is a far pointer to the string that the Print Manager will display in its client area to identify the document being printed. Generally, this string includes the name of the application doing the printing and the file being printed. In this case, it's simply the name ”FormFeed.“ The third parameter is the length of this string.

If STARTDOC is successful (indicated by a positive return value), then FORMFEED calls the NEWFRAME Escape subfunction, which advances the printer to a new page. Once again, the return value is tested:

if (Escape (hdcPrint, NEWFRAME, 0, NULL, NULL) > 0)

The third, fourth, and fifth parameters are not used in this Escape call.

Finally, if everything has proceeded without error to this point, the document is ended:

Escape (hdcPrint, ENDDOC, 0, NULL, NULL) ;

Again, the last three parameters are not used. Note that the ENDDOC Escape function is called only if no printing errors have been reported. If one of the other Escape functions returns an error code, then GDI has already aborted the document. If the printer is not currently printing, such an error code often results in the printer being reset.

Simply testing the return values from the Escape calls is the easiest way to check for errors. However, WINDOWS.H includes identifiers for the error codes, which you can use if you want to report the particular error to the user. For example, the NEWFRAME Escape call could return the SP_OUTOFDISK error (-4), indicating insufficient disk space for GDI to store the printer output necessary to trigger the printer to do a formfeed. For most printers, this occurrence is extremely unlikely. For your own amusement, however, you might try specifying the PostScript printer driver as your current printer, with the output port OUTPUT.PRN. Run FORMFEED and check the size of the file. (It will be nearly 8 KB!)

If you've ever written a simple formfeed program for MS-DOS, you know that ASCII number 12 activates a formfeed for most printers. Why not simply open the printer port using the C library function open and then output an ASCII number 12 using write? Well, nothing prevents you from doing this. You first have to determine the parallel port or the serial port the printer is attached to—that's available from WIN.INI. You then have to determine if another program (the Print Manager, for instance) is currently using the printer. You don't want the formfeed to be output in the middle of a document, do you? Finally, you have to determine if ASCII number 12 is a formfeed character for the connected printer. It's not universal, you know. In fact, the formfeed command in PostScript isn't a 12; it's the word showpage.

In short, don't even think about going around Windows; stick with the Windows functions for printing.