windows程序设计1 消息循环

消息:windows中定义的结构体

typedef struct Msg
{
HWND hwnd;      //窗口句柄
UINT message;    //消息常量标识符
WPARAM wParam;   //32位消息的特定附加信息
LPARAM lParam;   //32位消息的特定附加信息
DWORD time;     //消息创建时的时间
TPoint pt;     //消息创建时的鼠标位置
} TMsg;
 消息分3种:
1、标准Windows消息:这种消息以WM_打头。
2、通知消息:通知消息是针对标准Windows控件的消息。这些控个包括:按钮(Button)、组合框(ComboBox)、编辑框(TextBox)、列表(ListBox)、ListView控件、Treeview控件、工具条(Toolbar)、菜单(Menu)等。每种消息以不同的字符串打头。
3、自定义消息:编程人员还可以自定义消息。WM_USER以后的数用来表示自定义消息,以前的是系统已经定义的消息,不要随便更改。

回调函数:回调函数一般都有规定的参数格式,以地址方式传递给调用者。

windows的消息机制:

回调函数机制:

消息与事件

事件本质上是对消息的封装,这个封装是在窗体过程中实现的。每种IDE封装了许多Windows的消息,例如:
事件
消息
OnActivate
WM_ACTIVATE
OnClick
WM_XBUTTONDOWN
OnCreate
WM_CREATE
OnDblClick
WM_XBUTTONDBLCLICK
OnKeyDown
WM_KEYDOWN
OnKeyPress
WM_CHAR
OnKeyUp
WIN_KEYUP
OnPaint
WM_PAINT
OnResize
WM_SIZE
OnTimer
WM_TIMER

程序的基本过程:首先程序声明了一个回调函数,以后就开始进入入口函数WinMain

WinMain函数大致做了一下几个工作:定义并初始化了一个窗口,向系统注册了这个窗口(RegisterClass),在内存中创建了窗口(CreateWindow),显示并更新窗口。然后进入消息循环,等待系统给程序发消息,如果收到了消息,通过DispatchMessage把消息给系统,然后系统通过调用回调函数WndProc判断是什么消息并作出响应。

#include <windows.h>  
#include <mmsystem.h>   
//等效于添加了在设置里添加了WINMM.LIB  
#pragma comment(lib, "WINMM.LIB")   

#define WM_MYMSG (WM_USER + 100)   //自定义消息
  
//回调函数声明  
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;  
  
int WINAPI WinMain( HINSTANCE hInstance,      // 当前实例句柄  
                    HINSTANCE hPrevInstance,  // 先前实例句柄,通常为空  
                    LPSTR lpCmdLine,          // 命令行  
                    int nCmdShow )            // 显示状态:最大化、最小化  
{  
    //窗口类的名字  
    static TCHAR szAppName[] = TEXT ("MyWindowsProgram") ;  
    //句柄  
    HWND hwnd ;  
    //消息:消息结构体内容有:句柄、消息识别符、附加消息、附加消息、消息投递时间、消息投递时的光标位置  
    //消息是由系统填写的。  
    MSG  msg ;  
    //窗口类  
    WNDCLASS wndclass ;  
    //窗口风格,可以是任何Class Styles的组合  
    wndclass.style = CS_HREDRAW | CS_VREDRAW ;//当运动或者大小调整时重回窗口  
    //指向窗口过程,必须使用回调函数调用窗口过程  
    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;  
    //0结尾的字符串或者按钮:这里是一个字符串,指明窗口类名  
    wndclass.lpszClassName = szAppName;  
  
    //注册窗口  
    if(!RegisterClass(&wndclass))  
    {  
        return 0;  
    }  
    //创建窗口  
    hwnd = CreateWindow(szAppName,                //窗口类名  
                        TEXT("我的windows程序"),  //窗口标签  
                        WS_OVERLAPPEDWINDOW,      //窗口风格:  
                        CW_USEDEFAULT,            //X坐标  
                        CW_USEDEFAULT,            //Y坐标  
                        CW_USEDEFAULT,            //宽度  
                        CW_USEDEFAULT,            //高度  
                        NULL,                     //父窗口句柄  
                        NULL,                     //窗口菜单句柄  
                        hInstance,                //程序实例句柄  
                        NULL);                    //创建参数  
  
    //显示窗口,参数为:窗口句柄,显示状态  
    ShowWindow(hwnd,SW_SHOWNA);  
    //更新窗口  
    UpdateWindow(hwnd);  
  
  
    while(GetMessage(&msg,NULL,0,0))    //获取消息参数:指向MSG结构,窗口句柄(NULL表示调用线程的任何窗口),第一条消息,最后一条消息  
    {  
        //虚拟键消息转换为字符消息字符消息被寄送到调用线程的消息队列里,当下一次线程调用函数GetMessage或PeekMessage时被读出  
        TranslateMessage(&msg);  
        //该函数分发一个消息给窗口程序。通常消息从GetMessage函数获得。消息被分发到回调函数(过程函数),作用是消息传递给操作系统,然后操作系统去调用我们的回调函数,也就是说我们在窗体的过程函数中处理消息。  
        DispatchMessage(&msg);  
    }  
    //msg.wParam是退出消息  
    return msg.wParam ;   
}  
  
//回调函数:由程序员定义,系统调用的函数,前两个是消息参数,后两个是Win16系统遗留下来的产物  
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)  
{  
    //设备内容句柄  
    HDC hdc;  
    //PAINTSTRUCT结构包含了绘制客户区域的信息,第一个参数就是HDC类的  
    PAINTSTRUCT ps;  
    RECT rect;  
    switch(message)  
    {  
    //创建窗口消息:CreateWindow函数被调用以后就会发出,这个消息不进入消息队列。  
    case WM_CREATE:  
        //参数为:播放的声音,(中间这个参数一般为NULL,除非使用SND_RESOURCE 播放标记标记),播放标记(同步和异步的区别在于:如果你连续点两下,同步会逐一播放;异步会在点第二下时停止第一下的声音,直接播放第二下)  
        //只能播放wav格式  
        //PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        return 0;  
    //绘制窗口消息  
    case WM_PAINT:  
          
        //BeginPaint函数准备指定的窗口画图  
        //参数为:窗口句柄、指向PAINTSTRUCT结构的画图信息  
        hdc = BeginPaint (hwnd, &ps) ;  
        //获取客户区的坐标:参数为:将要被获取坐标的窗口,指向RECT结构的指针来存放坐标  
        GetClientRect(hwnd,&rect);  
        //在指定区域画格式化的文本  
        //参数为:设备内容句柄,将要被展示的字符,文本长度(-1表示假定是0结尾的),RECT类型的地址,表明文本将要在那里被格式化,格式化方式:这里是水平、垂直都居中  
        DrawText(hdc,TEXT("Hello, Windows7!"),-1,&rect,DT_SINGLELINE | DT_CENTER | DT_VCENTER);  
        PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        //绘制窗口结束  
        EndPaint (hwnd, &ps) ;   
        return 0;  
          
    case WM_LBUTTONDOWN:  
        //是指定区域变为无效区  
        //PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        //使指定区域变为无效区,然后会自动调用paint函数  
        //InvalidateRect(hwnd,NULL,FALSE);  
        //发送消息,参数为:消息发给谁、发什么消息、两个附加消息信息  
        //SendMessage(hwnd,WM_MYMSG,wParam,lParam);  
        if(wParam & MK_RBUTTON)//同时右键也按下  
            PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        return 0;  
  
    case WM_RBUTTONDOWN:  
        if(wParam & MK_LBUTTON)  
            PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        return 0;  
  
    case WM_MYMSG:  
        PlaySound(TEXT ("D:/videos/msg.wav"),NULL,SND_FILENAME | SND_SYNC);  
        return 0;  
          
    //关闭窗口消息  
    case WM_DESTROY:  
        PostQuitMessage (0) ;  
        return 0;  
      
    }  
    return DefWindowProc (hwnd, message, wParam, lParam) ; //执行缺省消息  
}  
原文地址:https://www.cnblogs.com/gaoquanning/p/3045266.html