程序运行有两种,一种是流程式的,一种是回调式的。流程式的会按照设定好的路线,走完就可以了;回调式的会根据用户的输入进行判断,做出不同的处理。一个仿佛看电影,一个仿佛打游戏。
如果需要实现回调式的,就需要消息。操作系统就是典型。不管是信号池还是消息队列,都是将消息统一管理。打个比方:消息就像包裹,每个进程就仿佛一个家,我可以给另一个人家里发包裹,但是都要快递,如果所有人都去快递公司拿,快递公司直接炸了,如果快递到家门口,再去拿,效率就快多了。这个快递的过程,就是消息队列。
先看包裹
包裹需要包含的信息://MSG结构体:typedef struct tagMSG { HWND hwnd; //句柄,属于哪个窗口的 UINT message; //消息ID,不同数值表示不同消息 WPARAM wParam; //附加信息1 LPARAM lParam; //附加信息2 DWORD time; //时间 POINT pt; //鼠标位置} MSG;
大约就是哪一户的包裹,什么类型的,里面有什么。
包裹处理方式
每个消息都会对应一个处理函数,不然你拿了包裹干啥,即消息处理函数。LRESULT CALLBACK WindowProc( HWND hwnd, // handle to window,句柄 UINT uMsg, // message identifier,消息ID WPARAM wParam, // first message parameter,参数1 LPARAM lParam // second message parameter,参数2);{ //里面写处理方式}
拿快递、送快递和寄快递
方式1:
BOOL PostMessage( HWND hWnd, // handle to destination window,句柄 UINT Msg, // message,消息 WPARAM wParam, // first message parameter,参数1 LPARAM lParam // second message parameter,参数2);//基本和消息相关的函数都有这几个参数//PostMessage类似非挂号信,和所有的快递一起进去快递公司(系统消息队列),然后配发(发给对应窗口即进程的消息队列),然后用户来取。至于用户取了没,不管,送了就走了。//对应的取快递的函数:BOOL GetMessage( LPMSG lpMsg, // message information,消息存放缓冲区 HWND hWnd, // handle to window,窗口句柄 UINT wMsgFilterMin, // first message,最大ID UINT wMsgFilterMax // last message,最小ID,如果都为0表示没有范围限制);//消息ID分类:系统的(0-0x03ff),自己定义的(0x400-ox7FF),应用程序之间通信用(0x800-0xBFF),系统注册消息(0xc000-oxffff)//这个取的方式很蠢,一直在楼下等,阻塞了进程,浪费CPU//前台,只看着,来快递了就喊你去拿,非阻塞,进程该干啥干啥BOOL PeekMessage( LPMSG lpMsg, // message information HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax, // last message UINT wRemoveMsg // removal options,是否移除);//是否移除标志:PM_NOREMOVE和PM_REMOVE,前者是不从消息队列中移除,后者是移除,和getmessage一样。/********************** 两个函数共同的处理流程: *在进程找符合要求的(窗口句柄和ID范围),有就取包裹。 *找不到就找系统消息队列要一下。 *系统消息队列也没有,就看看是不是要重绘,需要就WM_PAINT。 *没有要重绘的就看看定时器,有的WM_TIMER。 *也没有定时器就整理下程序资源。 ***********************///取了包裹之后:BOOL TranslateMessage( CONST MSG *lpMsg // message information,消息的地址);//判断是不是按键消息,是的话就WM_CHAR,不是就过。LRESULT DispatchMessage( CONST MSG *lpmsg // message information);//得到消息,找窗口处理函数,找到就执行,返回结果。
方式2:
//自己送LRESULT SendMessage( HWND hWnd, // handle to destination window UINT Msg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter );//这个就简单多了,自己跑一趟,找到对应的处理函数,执行,返回结果。//但是自己跑很累,虽然更快,所以重要的消息可以用下。
常用的消息
- WM_DESTORY,销毁的时候触发,善后处理。 - WM_SYSCOMMAND,系统命令消息,比如最大最小化,关闭等等。传入命令和鼠标位置。SC_CLOSE,SC_MOVE,SC_MINIMIZE等等,类似于一个集合。 - WM_CLOSE,窗口关闭。 - WM_LBUTTONDOWN,鼠标左键按下。 - WM_CHAR,字符消息,TranslateMessage可还记得? - WM_CREATE,窗口创建,还没显示。CreateWindow和ShowWindow中间,可以用来创建子窗口(按钮也算哦),初始化窗口等等。 - WM_SIZE,大小变化,创建的时候也会调用。 - WM_QUIT,结束消息循环处理。 - WM_PAINT,绘制,需要绘制的区域称为窗口无效区域 //WM_PAINT专属方法:BeginPaint,EndPaintHDC hDC;PAINTSTRUCT ps;hDC=BeginPaint(hwnd,&ps); //怎么画加在这里EndPaint(hwnd,&ps);