#include <windows.h>
#include 
"SYSMETS.h"
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPreInstance, PSTR szCmdLine, int iCmdShow)
{
    
static TCHAR szAppName[] = TEXT("SysMets2");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    wndclass.style 
= CS_HREDRAW | CS_VREDRAW;//这种窗口类别样式告诉windows,如果水平或者垂直大小发生改变,则强制更新显示区域。
    wndclass.lpfnWndProc = WndProc;
    wndclass.cbClsExtra 
= 0;
    wndclass.cbWndExtra 
= 0;
    wndclass.hInstance 
= hInstance;
    wndclass.hIcon 
= LoadIcon(NULL, IDI_APPLICATION);
    wndclass.hCursor 
= LoadCursor (NULL, IDC_ARROW) ; 
    wndclass.hbrBackground 
= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndclass.lpszMenuName 
= NULL;
    wndclass.lpszClassName 
= szAppName;
    
if (!RegisterClass(&wndclass))
    {
        MessageBox(NULL, TEXT(
"Thi program requires Windows NT!"), szAppName, MB_ICONERROR);
        
return 0;
    }
    hwnd 
= CreateWindow(szAppName,  
                                        TEXT(
"Get System Metrics No. 2"),
                                        WS_OVERLAPPEDWINDOW 
| WS_VSCROLL,
                                        CW_USEDEFAULT, CW_USEDEFAULT, 
                                        CW_USEDEFAULT, CW_USEDEFAULT,
                                        NULL,
                                        NULL,
                                        hInstance,
                                        NULL);
    ShowWindow(hwnd, iCmdShow);
    UpdateWindow(hwnd);
    
while (GetMessage(&msg, NULL, 00))
    {
        TranslateMessage(
&msg);
        DispatchMessage(
&msg);
    }
    
return msg.wParam;

}
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM IParam)
{
    
static int cxChar, cxCaps, cyChar, cyClient, iVscrollPos;
    HDC hdc;
    
int i, y;
    PAINTSTRUCT ps;
    TCHAR szBuffer[
10];
    TEXTMETRIC tm;
    
switch (message)
    {
        
case WM_CREATE:
            hdc 
= GetDC(hwnd);
            GetTextMetrics(hdc, 
&tm);
            cxChar 
= tm.tmAveCharWidth;
            cxCaps 
= (tm.tmPitchAndFamily & 1 ? 3 : 2* cxChar / 2;
            cyChar 
= tm.tmHeight + tm.tmExternalLeading;
            ReleaseDC(hwnd, hdc);
            
            
            SetScrollRange(hwnd, SB_VERT, 
0, NUMLINES - 1, FALSE);//设置滚动条行数
            SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);//设置滚动条的其实位置
            return 0;
        
case WM_SIZE:
            
/*
            当窗口大小改变时,windows给窗口消息处理程序发送了一个WM_SIZE消息。WM_SIZE消息必然跟着一个WM_PAINT消息。因为定义窗口类别的时候
            指定窗口类别的样式:CS_HREDRAW | CS_VERDRAW
            窗口消息处理程序的LParam参数的低字组中包含显示区域的宽度,高字组中包含显示区域的高度
                    case WM_SIZE:
                        cxClient = LOWORD(IParam);
                        cyClient = HIWORD(IParam);
                        return 0;
            LOWORD和HIWORD宏在Windows表头文件WINDEF.H中 定义。这些宏的定义看起来像这样:
            #define LOWORD(I)((WORD)(I))
            #define HIWORD(I)((WORD)(((DWORD)(I) >> 16 & 0xFFFF))
            
*/
            cyClient 
= HIWORD(IParam);
            
return 0;
        
case WM_VSCROLL:
            
/*windows对滚动条的处理:
             处理所有滚动条鼠标事件
             当使用者在滚动条内单击鼠标时,提供一种「反相显示」的闪烁 
             当使用者在滚动条内拖动卷动方块时,移动卷动方块
             为包含滚动条窗口的窗口消息处理程序发送滚动消息
             
*/
            
/*
            和所有的消息一样,WM_VSCROLL 和WM_HSCROLL也带有wParam和IParam消息淡出,对于来自作为窗口的一部分额建立的滚动条消息
            可以忽略IParam,它只用于作为子窗口而建立的滚动条(通常在对话框内)
            wParam低字组指出鼠标对滚动条进行的操作。这个数值被看成一个通知码,以SB开头代表scroll bar的标志符。在WINUSER.H中定义
            #define SB_LINEUP       0 
            #define SB_LINELEFT           0                      
            #define SB_LINEDOWN           1                      
            #define SB_LINERIGHT          1                      
            #define SB_PAGEUP         2                      
            #define SB_PAGELEFT           2                      
            #define SB_PAGEDOWN           3                      
            #define SB_PAGERIGHT          3                      
            #define SB_THUMBPOSITION   4                      
            #define SB_THUMBTRACK         5          
            #define SB_TOP                6              
            #define SB_LEFT           6       
            #define SB_BOTTOM        7   
            #define SB_RIGHT          7   
            #define SB_ENDSCROLL          8         
            
*/
            
switch(LOWORD(wParam))
            {
                
case SB_LINEUP:
                    iVscrollPos 
-= 1;
                    
break;
                
case SB_LINEDOWN:
                    iVscrollPos 
+= 1;
                    
break;
                
case SB_PAGEUP:
                    iVscrollPos 
-= cyClient / cyChar;
                    
break;
                
case SB_PAGEDOWN:
                    iVscrollPos 
+= cyClient / cyChar;
                    
break;
                
case SB_THUMBPOSITION:
                    iVscrollPos 
= HIWORD(wParam);
                    
break;
                
default:
                    
break;
            }
            iVscrollPos 
= max (0, min(iVscrollPos, NUMLINES - 1));
            
if (iVscrollPos != GetScrollPos(hwnd, SB_VERT))//GetScrollPos获取先前滚动条的位置
            {
                SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);
//重设滚动条位置
                InvalidateRect(hwnd, NULL, TRUE);//使整个窗口无效,InvalidateRect呼叫产生一个WM_PAINT消息,
            }
            
return 0;
        
case WM_PAINT:
            hdc 
= BeginPaint(hwnd, &ps);
            
for (i = 0; i < NUMLINES; i++)
            {
                y 
= cyChar * (i - iVscrollPos);
                TextOut(hdc, 
0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));
                TextOut(hdc, 
22 * cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));
                SetTextAlign(hdc, TA_RIGHT 
| TA_TOP);
                TextOut(hdc, 
22 * cxCaps + 40 * cxChar, y, szBuffer, 
                    wsprintf(szBuffer, TEXT(
"%5d"), 
                    GetSystemMetrics (sysmetrics[i].Index)));
                SetTextAlign(hdc, TA_LEFT 
| TA_TOP);
            }
            EndPaint(hwnd, 
&ps);
            
return 0;
        
case WM_DESTROY:
            PostQuitMessage(
0);
            
return 0;
    }
    
return DefWindowProc(hwnd, message, wParam, IParam);
}