#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);
}