win32消息机制

在上一篇blog中,我大致介绍了一下构建一个简单窗口的必备要素及其逻辑。今天就来聊聊win32的消息机制。

首先消息是什么?
windows系统的消息有且只有6部分组成,分别是窗口句柄,消息ID(作用),消息产生时鼠标的位置,消息产生的时间,以及跟消息内容相关的参数。

typedef struct tagMSG {
    HWND        hwnd;//窗口句柄
    UINT        message;//消息内容
    WPARAM      wParam;//消息类别(附带信息
    LPARAM      lParam;//消息类别
    DWORD       time;//消息产生时间
    POINT       pt;//鼠标所在位置
#ifdef _MAC
    DWORD       lPrivate;
#endif
} MSG, *PMSG, NEAR *NPMSG, FAR *LPMSG;

然后,消息是从哪里产生的?windows中从根源上产生消息的是两个函数

BOOL SendMessage(HWND hWnd, //消息发送目的窗口
                            UINT msgID, //消息ID
                            WPARAM wParam, //消息参数
                            LPARAM iParam);
BOOL PostMessage(HWND hWnd, //消息发送目的窗口
                            UINT msgID, //消息ID
                            WPARAM wParam, //消息参数
                            LPARAM iParam);
//send比较专一,会痴痴地等待消息回复(消息的处理结果)。而post则是发出消息就不管不顾了。

其他函数正是通过调用他们,来实现生产消息。

接下来,消息都会到哪儿去?

根据消息产生的函数,有两种途径。不过我们要先来聊聊消息的“居所”,其名队列(FIFO),系统消息队列存储所有消息,而一般的程序队列则存储该线程的消息。这两者之间的关系好比总部与分部之间的关系,总部先收容所有的消息,每隔一段时间分发给分部(记住,msg中有hWnd,可以以此来确定目的地)。

至此,第一种途径就已经明了了。消息产生后,先到系统队列,再到程序队列,然后被该程序的getmessage抓到。这类消息是由postmessage发送的。以WM_QIUT为代表

而第二种途径则是sendmessage直达消息处理函数函数。以WM_CREATE为代表

再接下来是获取消息。这是getmessage与peekmessage的主场

BOOL
GetMessage(
    LPMSG lpMsg, //information
    HWND hWnd, //handle to window
    UINT wMsgFilterMin,// first message
    UINT wMsgFilterMax,// last message
    UINT wRemoveMsg//PM_REMOVE\PM_NOREMOVE
);//移除消息,阻塞函数,若无消息,会等候
BOOL
PeekMessage(
    LPMSG lpMsg, //information
    HWND hWnd, //handle to window
    UINT wMsgFilterMin,// first message
    UINT wMsgFilterMax,// last message
    UINT wRemoveMsg//PM_REMOVE\PM_NOREMOVE
);//以查看的方式获取消息,可以不移除,非阻塞函数,当系统无消息,返回FALSE,继续执行

我们将GetMessage比作战士,而PeekMessage则是侦查兵。第一个参数是当前的消息,或者说敌情,而hWnd与之后的两个参数限定了他们处理的范围。PeekMessage的最后一个参数决定了是否要给这个函数处理消息的权限(仅仅是移除而已)。

因此我们一般将peekmessage的最后一个参数设置为PM_NOREMOVE,让getmessage去抓消息。

现在具体讲讲GetMessage的工作:一般认为,它没有消息就待机,实际并非如此。

首先去检查程序队列里有没有消息,如果有,则处理,没有,就去向系统队列要,如果有,此时系统队列会直接发送给程序队列。如果没有,GetMessage会检查需不需要重新绘制窗口,如果需要,发送重新绘制窗口的消息,如果不需要,去检查定时器时间,如果有,就发送相关消息,如果没有,就处理系统资源。如果不需要处理,才开始等待。而PeekMessage则是在这个步骤里选择返回。

最后就是消息处理

//消息循环(获取、翻译、派发)
	MSG nMsg = { 0 };
	while (GetMessage(&nMsg, nullptr, 0, 0))
	{
		TranslateMessage(&nMsg);
		DispatchMessage(&nMsg);//将消息给窗口处理函数来处理
	}

翻译消息翻译的是键盘消息。By the way of analogy,the same key "a" can present as a or A,which depends on whether the CapsLock is opened.所以需要简单翻译一下。

接下来是DispatchMessage,本质是调用自己编写的消息处理函数。

至此,消息循环的大体内容就结束了

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值