The SYSMETS1.C Window Procedure

The WndProc window procedure in the SYSMETS1.C program processes three messages: WM_CREATE, WM_PAINT, and WM_DESTROY. The WM_DESTROY message is processed in the same way as the HELLOWIN program in Chapter 1.

The WM_CREATE message is the first message the window procedure receives. It is generated by Windows when the CreateWindow function creates the window. During the WM_CREATE message, SYSMETS1 obtains a device context for the window by calling GetDC, and gets the text metrics for the default system font by calling GetTextMetrics. SYSMETS1 saves the average character width in cxChar and the total height of the characters including external leading in cyChar.

SYSMETS1 also saves an average width of uppercase letters in the static variable cxCaps. For a fixed-pitch font, cxCaps would equal cxChar. For a variable-width font, cxCaps is about 150% of cxChar. The low bit of the tmPitchAndFamily field of the TEXTMETRIC structure is 1 for a variable-width font and 0 for a fixed-pitch font. SYSMETS1 uses this bit value to calculate cxCaps from cxChar:

cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;

SYSMETS1 does all window painting during the WM_PAINT message. As normal, the window procedure first obtains a handle to the device context by calling BeginPaint. A for statement loops through all the lines of the sysmetrics structure defined in SYSMETS.H. The three columns of text are displayed with three TextOut functions. In each case, the third parameter to TextOut is set to:

cyChar * (1 + i)

This parameter indicates the pixel position of the top of the character string relative to the top of the client area. Thus, the program leaves a margin at the top equal to cyChar. The first line of text (when i equals 0) begins cyChar pixels below the top of the client area.

The first TextOut statement displays the uppercase identifiers in the first of the three columns. The second parameter to TextOut is cxChar. This leaves a one-character margin between the left edge of the client area and the text string. The text is obtained from the szLabel field of the sysmetrics structure. I use the Windows function lstrlen (which is similar to strlen) to obtain the length of the string, which is required as the last parameter to TextOut.

The second TextOut statement displays the description of the system metrics value. These descriptions are stored in the szDesc field of the sysmetrics structure. In this case, the second parameter to TextOut is set to:

cxChar + 18 * cxCaps

The longest uppercase identifier displayed in the first column is 16 characters, so the second column must begin at least 16 ´ cxCaps to the right of the beginning of the first column of text.

The third TextOut statement displays the numeric values obtained from the GetSystemMetrics function. The variable-width font makes formatting a column of right-justified numbers a little tricky. All the digits from 0 through 9 have the same width, but this width is greater than the width of a space. Numbers can be one or more digits wide, so different numbers can begin at different horizontal positions.

Wouldn't it be easier if we could display a column of right-justified numbers by specifying the pixel position where the number ends rather than where it begins? This is what the SetTextAlign function lets us do. After SYSMETS1 calls

SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;

then the coordinates passed to subsequent TextOut functions will specify the top-right corner of the text string rather than the top-left corner.

The TextOut function to display the column of numbers has a second parameter set to:

cxChar + 18 * cxCaps + 40 * cxChar

The 40 ´ cxChar value accommodates the width of the second column and the width of the third column. Following the TextOut function, another call to SetTextAlign sets things back to normal for the next time through the loop.