程序运行有两种,一种是流程式的,一种是回调式的。流程式的会按照设定好的路线,走完就可以了;回调式的会根据用户的输入进行判断,做出不同的处理。一个仿佛看电影,一个仿佛打游戏。
如果需要实现回调式的,就需要消息。操作系统就是典型。不管是信号池还是消息队列,都是将消息统一管理。打个比方:消息就像包裹,每个进程就仿佛一个家,我可以给另一个人家里发包裹,但是都要快递,如果所有人都去快递公司拿,快递公司直接炸了,如果快递到家门口,再去拿,效率就快多了。这个快递的过程,就是消息队列。
先看包裹
包裹需要包含的信息:
//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,EndPaint
HDC hDC;
PAINTSTRUCT ps;
hDC=BeginPaint(hwnd,&ps);
//怎么画加在这里
EndPaint(hwnd,&ps);