#include <windows.h>  
#pragma comment( lib,
"winmm.lib")//增加鏈接庫文件,PlaySound函數要使用winmm.lib鏈接庫
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdline, int iCmdShow)
{
    
static TCHAR szAppName[] = TEXT("HelloWin");
    HWND hwnd;
    MSG msg;
    WNDCLASS wndclass;
    wndclass.style 
= CS_HREDRAW | CS_VREDRAW;
    
//定義依據這個類別來建立的所有窗口所使用的窗口消息處理程序的地址——WndProc 函數,
    
//C語言中,像這樣在結構中使用函數名,提供的是指向函數的指針
    wndclass.lpfnWndProc = WndProc;

    
//這兩個字段用于在窗口類別結構和windows內部保存的窗口結構中預留一些額外空間
    
//0表示不使用
    wndclass.cbClsExtra = 0;
    wndclass.cbWndExtra 
= 0;//第7章有介紹

    
//程序的執行實體句柄(WinMain的參數之一)
    wndclass.hInstance = hInstance;

    
//LoadIcon加載圖標句柄。
    
//1:NULL表示將圖標設為預先定義的圖標,
    
//如果想加載自定義的圖標時該參數被設定為程序的執行實體句柄hInstance(圖標應該存放在磁盤上的.EXE程序文件中)
    
//2:圖示
    
//對于預先定義圖標,此參數以IDI開始的標志符(ID代表圖標句柄),標識符在WINUSER.H中定義
    wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);//窗口左上端小圖標,IDI_APPLICATION圖標是一個簡單的窗口小圖形
    wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);//鼠標圖標

    
//指定依據這個類別建立的窗口背景顏色,windows標準的幾個畫刷也成為備用(stock)畫刷
    wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);//取得圖形對象,這里取得白色畫刷
    
    
//指定窗口類別菜單,NULL表示沒有應用程序菜單
    wndclass.lpszMenuName = NULL;
    wndclass.lpszClassName 
= szAppName;//窗口類別名稱
    if (!RegisterClass(&wndclass))//注冊窗口類別,RegisterClass將獲得一個指向WINCLASS結構的指針
    {
        MessageBox(NULL, TEXT(
"this program requires windows NT!"), szAppName, MB_ICONERROR);
        
return 0;
    }
    
//建立窗口
    hwnd = CreateWindow(szAppName, //窗口類型名字
                    TEXT("The Hello Program"),//窗口標題
                    WS_OVERLAPPEDWINDOW,//windows風格
                    CW_USEDEFAULT,// 初始化x
                    CW_USEDEFAULT,//初始化y
                    CW_USEDEFAULT,//初始化x方向尺寸
                    CW_USEDEFAULT,// 初始化y方向尺寸
                    NULL,//父窗口句柄,通常如果窗口之間存在父子關系,子窗口會出現在父窗口上面
                    NULL,//窗口菜單句柄
                    hInstance,//程序執行實體句柄
                    NULL//建立參數,用這個參數存取程序中可能引用到的數據
                    );
    
/*
    在CreateWindow呼叫傳回之后,Windows內部已經建立了這個窗口。這就是說,Windows已經配置了一塊內存,
    用來保存在CreateWindow呼叫中指定窗口的全部信息跟一些其它信息,而Windows稍后就是依據窗口句柄找到這些信息的。
    
*/
    
    
/*顯示窗口
    1:窗口句柄
    2:作為參數傳給WinMain的iCmdShow,它確定最初在屏幕上顯示窗口的大小
    (一般大小SW_SHOWNORMAL、最小化SW_SHOWMINIMIZED還是最大化SW_SHOWMAXIMIZED)
    SW_SHOWMINNOACTIVE表示窗口只顯示在工作列表上
    
*/
    ShowWindow(hwnd, SW_SHOWMINNOACTIVE);
    UpdateWindow(hwnd);

    
//從消息隊列中獲取消息
    while (GetMessage(&msg, NULL, 00))
    {
        
/*
        msg的型態是MSG結構,在WINUSER.H中定義如下
        typedef struct tagMSG          
        {   
            HWND   hwnd ; // 接收消息的窗口句柄,在HELLOWIN程序中,這一參數與CreateWindow傳回的hwnd值相同,因為 這是該程序擁有的唯一窗口。
            //消息標識符,這是一個數值,用以標識消息。對于每個消息,均有一個對應的標識符,這些標識符定義于Windows表頭文件
            (其中大多數在WINUSER.H中),以前綴WM(「window message」,窗口消息)開頭。
            UINT   message ; 
            WPARAM wParam ; //一個32位的「message parameter(消息參數)」,其含義和數值根據消息的不同而不同
            LPARAM lParam ; // 一個32位的消息參數,其值與消息有關。
            DWORD  time ; // 消息放入消息隊列中的時間。
            POINT  pt ; //消息放入消息隊列時的鼠標坐標。POINT在WINDEF.H中定義如下typedef struct tagPOINT{ LONG x, y; }POINT, *PPOINT;
        } 
        
*/
        TranslateMessage(
&msg);//轉譯某些鍵盤消息,詳看第六章
        DispatchMessage(&msg);//將消息發送給窗口消息處理程序WndProc
    }
    
return msg.wParam;
}

/* 窗口消息處理程序
窗口消息處理程序的四個參數與MSG結構的前四個字段是相同的
*/
LRESULT CALLBACK WndProc(HWND hwnd, UINT message,  WPARAM wParam, LPARAM  IParam)
{
    
/*
    四個參數與MSG結構前四個字段相同
    hwnd:接受消息的窗口,與CreateWindows函數返回值相同
    message:標志消息的數值
    wParam,lParam:32位的消息參數,提供更多的消息信息
    
*/
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect;
    
switch (message)
    {
        
//處理WM_CREATE消息并將控制傳回給Windows,windows從CreateWindows呼叫中傳回到HELLOWIN中
        case WM_CREATE:
            
//1:聲音的文件名稱
            PlaySound(TEXT("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC);
            
return 0;
        
case WM_PAINT:
            
//對WM_PAINT的處理幾乎總是從BeginPaint開始,以一個EndPaint結束
            
//這兩個函數的第一個參數是程序的窗口句柄,第二個是指向PAINTSTRUCT的結構指針
            
//該結構包含一些窗口消息處理程序,可以用來更新顯示區域的內容

            hdc 
= BeginPaint(hwnd, &ps);//繪制窗口,使用注冊窗口類別的WNDCLASS結構的hbrBackground字段中指定的畫刷來刷背景。傳回設備內容(即顯示器及其設備驅動)句柄
            
            GetClientRect(hwnd, 
&rect);//rect指向一個RECT型態的recgtangle結構,RECT有left,top, right, bottom四個字段(像素點數)

            
/*DrawText用于輸出文字,
            1:從BeginPaint(傳回的設備內容句柄)
            2:要輸出的文字
            3:-1表示字符串是以0為結尾的。
            4:一系列位旗標,參數值讓Hello,windows顯示在顯示區域中央
            顯示區域有改變時,wndProc會接受新的WM_PAINT消息,
            通過呼叫GetClient去的變化后的窗口大小,在新窗口中顯示文字。
            
*/
            DrawText(hdc, TEXT(
"Hello, window!"), -1&rect, 
                DT_SINGLELINE 
| DT_CENTER | DT_VCENTER);

            EndPaint(hwnd, 
&ps);//釋放設備內容句柄,使之不再有效
            return 0;
        
case WM_DESTROY:
            
//用于窗口的關閉,PostQuitMessage在消息隊列中插入WM_QUIT消息,該消息的值為0
            
//GetMessage對于每個除了WM_QUIT之外的從消息隊列中取出的所有消息都傳回非0值
            
//該函數接收WM_QUIT后導致WinMain退出消息程序循環,終止程序后執行return msg.wParam,wParam是傳遞
            
//給PostQuitMessage函數的值,這里為0。
            PostQuitMessage(0);
            
return 0;
    }
    
//執行內定的消息處理,將窗口消息處理程序不處理的消息傳給這個windows函數,否則一般動作,如終止程序將不會正常執行
    return DefWindowProc(hwnd, message, wParam, IParam);
}