【Demo 0003】Windows 消息机制(1)
看到这个标题是你可能会问, 怎么又说消息机制呢, Demo0002中不是己说过了吗? 还说? 呵呵,因为Demo 0002中只是为了讲Win32程序结构而做的引导,讲的不够全不够细,缺少太多的核心内容,比如Windows消息原理图画的视角不能很好展示Windows消息机制,缺少对 GetMessage, PeekMessage, SendMessage, GetMessage 的解说等等。
Windows 是一个消息驱动的OS, 为了存放消息系统提供了一个系统消息队列, OS在监控到事件的发生时就会产生相应的消息并存放到系统消息队列中。 而每个Windows 应用程序自己也有一个消息队列,OS在处理系统消息队列时会将属于本应用程序的消息投递到此消息队列中. 而消息循环体就不断的从这个消息队列中提取消息,分发给对应的窗体过程函数去处理。这里我引用于了网上的图来说明:
如图所示应用程序通过消息循环不断的从应用程序队列中获取消息并分发给对应的窗体函数, Windows 实现消息循环有两种方式:
a. 等待模式 - 队列中无消息时程序挂起
{
MSG Msg;
while (GetMessage(&Msg, NULL, 0, 0))
{
TranslateMessage(&Msg);
DispatchMessage(&Msg);
}
}
b. 非等待模式 – 队列中无消息时程序不挂起
{
MSG Msg;
while (true)
{
if (PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
if (WM_QUIT == Msg.message)
{
break;
}
TranslateMessage(&Msg);
DispatchMessage(&Msg);
} else {
OnIdle(ghWnd);
}
}
}
等待模式和非等待模式差别在于当消息队列里没有消息时, 是继续等待消息才工作还是继续做别的事. 我们看一下以上述两份代码,都比较简单,我们联合解说一下:
1. MSG Msg; 消息结构
typedef struct tagMSG
{
HWND hwnd ; // 接受消息的窗体句柄
UINT message ; // 消息ID
WPARAM wParam ; // 消息参数
LPARAM lParam ; // 消息参数
DWORD time ;
POINT pt ;
} MSG, * PMSG ;
2. GetMessage(LPMSG, HWND, UINT, UINT)
从线程消息队列中获取消息,若消息队列中存在消息时函数立即返回,否则此函数会被挂起直到等待新消息的到来。如果获到的消息为WM_QUIT时, GetMessage返回0;
当用户在收到WM_QUIT后也就退出消息循环,结束了应用程序线程. 我们可以编译一下Demo源码运行看看Demo对CPU的消耗, 几乎为0, 因为在Demo在没有消息时一起被挂起。
LPMSG – 从线程消息队列中读取的消息,
HWND - 读取此消息对应的窗体,NULL 表示消息所有队列中的消息
3. PeekMessage(LPMSG, HWND, UINT, UINT, UINT)
窥视线程消息队列消息,也可以设置参数在窥视时将消息从队列中删除。 此函数只是查看队列消息,若队列中不存在消息时此函数会立即还回, 这是它与GetMessage最大的不同.
大家将Demo中#define WAITMODE 宏注释,编译运行下可看到窗体里不断的画不同颜色的矩形,此进程CPU一起有消耗。
4. TranslateMessage(const LPMSG)
此函数主要功能实现一些键盘消息转换,比如我们在按下键人列时会将收到WM_KEYDOWN消息后,此函数会将此消息发给windows,windows 会转发出WM_CHAR消息
5. DispatchMessage(const LPMSG)
此函数执行时会通知windows分发这个消息,Windows收到处消息后会窗体过程序函数去处理对应的消息.
参考文档:
http://www.cppblog.com/mzty/archive/2006/11/24/15619.html
http://www.cppblog.com/tx7do/archive/2007/04/11/21665.aspx