首页 > 技术文章 > win32消息机制

ShiningArmor 2019-12-09 16:15 原文

1.事件和消息
Windows中的事件是一个“动作”,这个动作可能是用户操作应用程序产生的,也可能是Windows自己产生的.   
    例如:鼠标右键点击就是一个事件   
    当我们做了这个动作后,windows要能正确响应必须记录如下信息:点的是谁、在哪里点的、动作是什么类型等等;
    否则windows就无法知道我们到底要它做什么事情; 
消息,就是用来描述这些“动作”的,比如:                
    这个动作是什么时候产生的?                
    哪个应用程序产生的?                
    在什么位置产生的?                
    等等。。。                
 
Windows为了能够准确的描述这些信息,提供了一个结构体:MSG,该结构体里面记录的事件的详细信息.                
typedef struct tagMSG {                
  HWND   hwnd;                 
  UINT   message;                 
  WPARAM wParam;                 
  LPARAM lParam;                 
  DWORD  time;                 
  POINT  pt;                 
} MSG, *PMSG;    
说明:                
    1】hwnd:
        句柄 ,每一个窗口都有一个唯一的句柄                
        表示消息所属的窗口                
        一个消息一般都是与某个窗口相关联的                
        在Windows中 HWND类型的变量通常用来标识窗口。                
    2】message
        消息类型,用来表示到底是什么动作;例如鼠标右键单击;                
        在Windows中,消息是由一个数值来表示的                
        但是由于数值不便于记忆,所以Windows将消息对应的数值定义为WM_XXX宏(WM == Window Message)                
        鼠标左键按下 WM_LBUTTONDOWN                键盘按下 WM_KEYDOWN
    3】wParam 和 lParam      
        对消息的进一步详细说明,具体存什么可以查消息类型的文档;          
        32位消息的特定附加信息,具体表示什么处决于message                 
    4】time   
        消息创建时的时间 ;也就是什么时候出发的这个动作;                
    5】消息创建时的鼠标位置                
        用一个POINT结构来表示;
        POINT结构记录了横纵坐标;
typedef struct tagPOINT
{
    LONG  x;
    LONG  y;
} POINT, *PPOINT, NEAR *NPPOINT, FAR *LPPOINT;
 
2.消息流程
1】系统/用户触发的某个动作                        //事件    
2】系统将这些信息存储到MSG结构体中                        //消息    
3】系统将该消息存储到相关应用程序的消息队列中                        //消息队列    
    MSG Msg;                             
4】while(GetMessage(&Msg,NULL,0,0))                                //循环从队列中获取消息,放到定义的空Msg结构中    
    {                                
        TranslateMessage(&Msg);                                                        //翻译消息,例如把按键盘某个键翻译成该键对应的字符      
        DispatchMessage(&Msg);                                                       //分派消息,不是直接调用我们写的函数,而是将翻译完的消息发回给操作系统        
    }                            
5】DispatchMessage将加工过的消息传递给操作系统                            
6】系统调用窗口过程函数                            
7】LRESULT CALLBACK WindowProc(                          //窗口过程函数    
        IN  HWND hwnd,                       //窗口句柄     
        IN  UINT uMsg,                          //消息类型
        IN  WPARAM wParam,               //和第四个参数都是消息附加信息           
        IN  LPARAM lParam                          
    );                          
 
如图,系统消息队列与应用程序消息队列:            
对上图的解析:
    用户的输入使一个事件被触发,windows将该事件封装在MSG消息结构中;
    然后将这个消息结构放在windos系统队列里面;系统队列是一个先进先出的数据结构;
    每一个程序都有一个应用程序队列,windows根据句柄将系统队列中的消息分发到各个应用程序的队列中;
    
    程序从应用程序队列中取出消息,然后判断消息的类型;
        因为不知道什么时候队列中有消息,就需要有个消息循环,一直循环从队列中取消息;
    如果是关心的消息就自己处理,否则就交给windows来处理;
        
3.创建窗口    
#include<stdio.h>
#include<windows.h>
#include "windebug.h"
 
LRESULT CALLBACK WindowProc(                                      
    IN  HWND hwnd,          
    IN  UINT uMsg,          
    IN  WPARAM wParam,
    IN  LPARAM lParam
    
);
 
int CALLBACK WinMain(                        //CALLBACK是一个宏,表示__stdcall,也就是内平栈,win32所有api函数都是该调用约定
            HINSTANCE hInstance,
            HINSTANCE hPrevInstance,
            LPSTR lpCmdLine,
            int nCmdShow
            ){
    //1.告诉window要画一个什么样的窗口                                    
    TCHAR className[] = "My First Window";     //窗口的类名                                                                    
    // 创建窗口类的对象                                     
    WNDCLASS wndclass = {0};                        //一定要先将所有值赋值,否则RegisterClass函数无法起作用;            
    wndclass.hbrBackground = (HBRUSH)COLOR_MENU;                        //窗口的背景色            
    wndclass.lpfnWndProc =  WindowProc;                        //窗口过程函数            
    wndclass.lpszClassName = className;                        //窗口类的名字            
    wndclass.hInstance = hInstance;                        //定义窗口类的应用程序的实例句柄            
 
    //2.注册窗口类
    RegisterClass(&wndclass);          
 
    //3.创建窗口类
    HWND hwnd = CreateWindow(                              
        className,                //类名,可以用自己定义的窗口My First Window,也可用系统定义好的窗口例如按钮button        
        TEXT("我的第一个窗口"),                //窗口标题        
        WS_OVERLAPPEDWINDOW,                //窗口外观样式         
        10,                //相对于父窗口的X坐标        
        10,                //相对于父窗口的Y坐标        
        600,                //窗口的宽度          
        300,                //窗口的高度          
        NULL,                //父窗口句柄,为NULL          
        NULL,                //菜单句柄,为NULL          
        hInstance,                //当前应用程序的句柄          
        NULL);                //附加数据一般为NULL        
                                
    if(hwnd == NULL)                    //是否创建成功          
        return 0;                          
 
    //4.显示窗口
    ShowWindow(hwnd, SW_SHOW);          
 
    //5.消息循环
    MSG msg;              
    while(GetMessage(&msg, NULL, 0, 0))              
    {              
        TranslateMessage(&msg);          
        DispatchMessage(&msg);          
    }      
    return 0;
}
                                    
//6.回调函数,由操作系统来调用
/*                    
窗口消息处理程序 窗口回调函数:                    
                    
1、窗口回调函数处理过的消息,必须传回0.                    
                    
2、窗口回调不处理的消息,由DefWindowProc来处理.                    
*/                    
 
LRESULT CALLBACK WindowProc(                                      
                            IN  HWND hwnd,          
                            IN  UINT uMsg,          
                            IN  WPARAM wParam,          
                            IN  LPARAM lParam          
                            )          
{                          
    switch(uMsg)                                
    {                                
        //窗口消息                            
    case WM_CREATE:                                 
        {                            
            DbgPrintf("WM_CREATE %d %d\n",wParam,lParam);                        
            CREATESTRUCT* createst = (CREATESTRUCT*)lParam;                        
            DbgPrintf("CREATESTRUCT %s\n",createst->lpszClass);                        
                                        
            return 0;                        
        }                            
    case WM_MOVE:                                
        {                            
            DbgPrintf("WM_MOVE %d %d\n",wParam,lParam);                        
            POINTS points = MAKEPOINTS(lParam);                        
            DbgPrintf("X Y %d %d\n",points.x,points.y);                        
                                    
            return 0;                        
        }                            
    case WM_SIZE:                                
        {                            
            DbgPrintf("WM_SIZE %d %d\n",wParam,lParam);                        
            int newWidth  = (int)(short) LOWORD(lParam);                            
            int newHeight  = (int)(short) HIWORD(lParam);                           
            DbgPrintf("WM_SIZE %d %d\n",newWidth,newHeight);                        
                                    
            return 0;                        
        }                            
    case WM_DESTROY:                                
        {                            
            DbgPrintf("WM_DESTROY %d %d\n",wParam,lParam);                        
            PostQuitMessage(0);                        
                                    
            return 0;                        
        }                            
        //键盘消息                            
    case WM_KEYUP:                                
        {                            
            DbgPrintf("WM_KEYUP %d %d\n",wParam,lParam);                        
                                    
            return 0;                        
        }                            
    case WM_KEYDOWN:                                
        {                            
            DbgPrintf("WM_KEYDOWN %d %d\n",wParam,lParam);                        
                                    
            return 0;                        
        }                            
        //鼠标消息                            
    case WM_LBUTTONDOWN:                                
        {                            
            DbgPrintf("WM_LBUTTONDOWN %d %d\n",wParam,lParam);                        
            POINTS points = MAKEPOINTS(lParam);                        
            DbgPrintf("WM_LBUTTONDOWN %d %d\n",points.x,points.y);                        
                                    
            return 0;                        
        }                            
    }                                
    return DefWindowProc(hwnd,uMsg,wParam,lParam);                                
}

 

 
    
 

推荐阅读