Add the IDM_PRINT Case

To carry out the printing operation, you need to add an IDM_PRINT case to the WM_COMMAND case of the main window function. Add the following statements:

case IDM_PRINT:

hPr = GetPrinterDC();

if(!hPr) {

sprintf(str, “Cannot print %s”, FileName);

MessageBox(hWnd, str, NULL, MB_OK | MB_ICONHAND);

break;

}

lpAbortDlg = MakeProcInstance(AbortDlg, hInst);

lpAbortProc = MakeProcInstance(AbortProc, hInst);

Escape(hPr, SETABORTPROC, NULL,

(LPSTR) (long) lpAbortProc, (LPSTR) NULL);

if(Escape(hPr, STARTDOC, 14, (LPSTR) “PrntFile text”,

(LPSTR) NULL) < 0) {

MessageBox(hWnd, “Unable to start print job”,

NULL, MB_OK | MB_ICONHAND);

FreeProcInstance(AbortDlg);

FreeProcInstance(AbortProc);

DeleteDC(hPr);

break;

}

bAbort = FALSE; /* Clears the abort flag */

hAbortDlgWnd = CreateDialog(hInst, “AbortDlg”, hWnd, lpAbortDlg);

ShowWindow(hAbortDlgWnd, SW_NORMAL);

UpdateWindow(hAbortDlgWnd);

EnableWindow(hWnd, FALSE);

GetTextMetrics(hPr, &TextMetric);

LineSpace = TextMetric.tmHeight + TextMetric.tmExternalLeading;

Escape(hPr, GETPHYSPAGESIZE, NULL, (LPSTR) NULL, (LPSTR) &PhysPageSize);

LinesPerPage = PhysPageSize.y / LineSpace;

dwLines = SendMessage(hEditWnd, EM_GETLINECOUNT, 0, 0L);

CurrentLine = 1;

for (dwIndex = IOStatus = 0; dwIndex < dwLines; dwIndex++) {

pLine[0] = 128; /* Maximum buffer size */

pLine[1] = 0;

LineLength = SendMessage(hEditWnd, EM_GETLINE,

(WORD) dwIndex, (LONG) ((LPSTR) pLine));

TextOut(hPr, 0, CurrentLine*LineSpace, (LPSTR) pLine, LineLength);

if(++CurrentLine > LinesPerPage ) {

Escape(hPr, NEWFRAME, 0, 0L, 0L);

CurrentLine = 1;

IOStatus = Escape(hPr, NEWFRAME, 0, 0L, 0L);

if(IOStatus < 0 || bAbort)

break;

}

}

if(IOStatus >= 0 && !bAbort) {

Escape(hPr, NEWFRAME, 0, 0L, 0L);

Escape(hPr, ENDDOC, 0, 0L, 0L);

}

EnableWindow(hWnd, TRUE);

DestroyWindow(hAbortDlgWnd);

FreeProcInstance(AbortDlg);

FreeProcInstance(AbortProc);

DeleteDC(hPr);

break;

The locally-defined GetPrinterDC function checks the WIN.INI file for the current printer and creates a device context for that printer. If there is not a current printer or the device context cannot be created, the function returns NULL and processing ends with a warning. Otherwise, the MakeProcInstance function creates procedure instance addresses for the AbortDlg dialog function and the AbortProc function. The SETABORTPROC escape used with the Escape function sets the abort function. The STARTDOC escape starts the printing job and sets the printing title (shown in the Print Manager application). If the STARTDOC escape fails, the FreeProcInstance function frees the AbortDlg and AbortProc procedure instances and the DeleteDC function deletes the device context before processing ends.

The CreateDialog function creates the AbortDlg dialog box and the EnableWindow function disables the main window. This prevents users from attempting to work in the main window while printing. Users can, however, continue to work in some other application.

Since the edit control may contain more than one line, it is important to provide adequate spacing between lines. This keeps one line from overwriting or touching another. The GetTextMetrics function retrieves current font information, such as height and external leading, which can be used to compute adequate line spacing. The height is the maximum height of characters in the font. The external leading is the recommended amount of space, in addition to the height, that should be used to separate lines of text in this font. The line spacing, assigned to the LineSpace variable, is the sum of the height and external leading fields, TextMetric.tmHeight and TextMetric.tmExternalLeading.

Since the edit control might contain more lines than can fit on a single page, it is important to determine how many lines can fit on a page and to advance to the next page whenever this line limit is reached. The GETPHYSPAGESIZE escape retrieves the physical dimensions of the page and copies the dimensions to the PhysPageSize structure. PhysPageSize contains both the width and height of the page. The lines per page, assigned to the LinesPerPage variable, is the quotient of the physical height of the page, PhysPageSize.y, and the line spacing, LineSpace.

The TextOut function can print only one line at a time, so a for statement provides the loop required to print more than one line of text. The EM_GETLINECOUNT message, sent to the edit control by using the SendMessage function, retrieves the number of lines to be printed and determines the number of times to loop. On each execution of the loop, the EM_GETLINE message copies the contents of a line from the edit control to the line buffer, pLine. The loop counter, dwIndex, is used with the EM_GETLINE message to specify which line to retrieve from the edit control. The EM_GETLINE message also causes SendMessage to return the length of the line. The length is assigned to the LineLength variable.

Once a line has been copied from the edit control, it is printed by using the TextOut function. The product of the variables CurrentLine and LineSpacing determines the y-coordinate of the line on the page. The x-coordinate is set to zero. After a line is printed, the value of the CurrentLine variable is increased by one. If CurrentLine is greater than LinesPerPage, it is time to advance to the next page. Any text printed beyond the physical bottom of a page is clipped. There is no automatic page advance, so it is important to keep track of the number of lines printed on a page and to use the NEWFRAME escape to advance to the next page when necessary. If there are any errors during printing, the NEWFRAME escape returns an error number and processing ends.

After all lines in the edit control have been printed, the NEWFRAME escape advances the final page and the ENDDOC escape terminates the print request. The DeleteDC function deletes the printer device context since it is no longer needed, and the DestroyWindow function destroys the AbortDlg dialog box.