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