VC编程Windows消息处理机制、阻塞试验、SetTimer、MessageBox、小心消息响应处理函数多个并存2012_7
合集下载
相关主题
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
说明是: 父窗消息循环,调用消息响应函数生成了第一个消息框,同时父窗调用的消息响应
函数阻塞,父窗消息循环阻塞;第一个消息框开始接手负责消息循环(是自己有消息循 环还是把父窗的消息循环重入了继续使用?)。
第一个消息框消息循环,调用消息响应函数生成了第二个消息框,同时第一个消息 框调用的消息响应函数阻塞,第一个消息框消息循环阻塞;第二个消息框开始接手负责 消息循环(是自己有消息循环还是把父窗的消息循环重入了继续使用?)。
}
BOOL running=FALSE;
void CUnicodewcharDlg::OnRecv() {
if (running==TRUE) {::MessageBox(NULL,"ERROR","",MB_OK); return;} running=TRUE; ::MessageBox(NULL,"OK","",MB_OK); ::MessageBox(NULL,"返回","",MB_OK); running=FALSE; }
l 消息队列是线程所有,并非窗口所有和进程所有。 l 一个线程的所有窗口,比如父窗口(主窗口)、对话框、消息框等都是使用这
个线程的同一个消息队列!!!! l 窗口有消息循环。窗口里的控件应该就没有消息循环了吧。
试验: 一、MFC 中,用 TIMER,发现,在 TIMER 响应函数中,用 MessageBox(),则会不断 地出现 MessageBox。 而且当前响应函数会停止在 MessageBox 上,直到 MessageBox 返回才继续执行后面 的语句!
windows 消息处理机制是这样的: 首先系统(也就是 windows)把来自硬件(鼠标,键盘等消息)和来自应用程序的消息 放到一个系统消息队列中去。 而应用程序需要有自己的消息队列,也就是线程消息队列,每一个线程有自己的消 息队列,对于多线程的应用程序就有和线程数目相等的线程消息队列。 winsows 消息队列把得到的消息发送到线程消息队列,线程消息队列每次取出一条 消息发送到指定窗口,不断循环直到程序退出。这个循环就是靠消息环 (while(GetMessage()) TranslateMessage();DispatchMessage(); 实现的。 GetMessage()只是从线程消息中取出一条消息,而 DispatchMessage 则把取出的消 息发送到目的窗口。如果收到 WM_CLOSE 消息则结束循环,发送 postqiutmessage(0),处 理 WM_DESTROY 销毁窗口!
VC 编程 Windows 消息处理机制、阻塞试验、SetTimer、MessageBox、小心消息响应处理 函数多个并存 wxleasyland@ 2012.7
wxleasyland 试验:
VC6 标准 WIN32 程序,Windows 消息处理机制: 1.在注册窗口类时,指定了消息处理函数 WndProc()。 2.WinMain()里有消息循环:
数解除阻塞。 如果处在中间的子窗关闭了,它的消息响应函数仍还在阻塞中!只有它后面的子窗
都关闭了,它的消息响应函数才会返回。
所以,如果是基于消息来处理事件,比如,网络 SOCKET 异步编程,消息处理函数 中,有用到消息框 MessageBox 或对话框,则要小心,以免多个事件消息同时发生。因 为消息框出现后,当前消息处理函数阻塞了,但消息循环仍在进行,如果有新的消息事 件产生,则会运行新的消息处理函数,则有可能会产生不希望的后果。
四、后来,试验网络 SOCKET 异步编程,确实,弹出 MessageBox 后,消息循环仍在 继续,如果有收到 FD_READ、FD_ACCEPT 等,都会执行消息处理函数。
如果消息处理函数中弹出 MessageBox,这时下一个消息来了,则会再运行一个新的 消息处理函数!而不是阻塞。即消息处理函数同时被多次调用,多个并存!
三、试验子窗口是自己有消息循环还是把父窗的消息循环重入了继续使用? 用 WIN32(标准 HELLO WORLD)程序来试:
在 WinMain()中:
while (GetMessage(&msg, NULL, 0, 0))
{
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
其实问题的关键在于:DispatchMessage 到底干了什么 ? 如果只是去调用相应的窗口,那自己写个 switch 不就可以了 ? DispatchMessage 与 switch 不同之处在于 DispatchMessage 会 先调用 windows, 进入管态(大概是 range 0),然后再由 windows 调用 窗口的函数。 为什么这么麻烦? 因为这样 windows 就可以知道你的程序运行到什么情况了,windows 来调用你的窗 口,这样你的窗口返回的时候,windows 就知道你已经处理过一个消息了,如果没有新 的消息进入消息队列,windows 就不再会给你的进程分配时间片。 如果是你自己写 switch 的话,windows 就不可能这样灵活的分配时间,资源利用率 就会降低。
发现,按 OnButton4 后,先出现一个"OK"消息框,再点 OnButton4,就出现"ERROR" 消息框。
如果"OK"消息框关闭了,则不会出现"返回"消息框,再点 OnButton4,仍是出现 "ERROR"消息框!!!!!!!
一 定 要 "ERROR" 消 息 框 和 "OK" 消 息 框 都 关 闭 了 , 才 会 出 现 " 返 回 " 消 息 框 , 再 点 OnButton4,才会出现"OK"消息框!!
=================================== 下面引用网络的文章: ===================================
/suninf/blog/item/c3b7c738fa751cf4b311c74d.html DispatchMessage 2008 年 10 月 18 日 星期六 14:33
用 SendMessage 或 PostMessage 来 试 消 息 响 应 , 也 是 一 样 : 响 应 函 数 中 有 MessageBox(),则会出现多个 MessageBox。
说明 MessageBox 阻塞了函数,却没有阻塞消息分发。
二、VC 建 WIN32 程序(标准 HELLO WORLD),试验发现,如果 WndProc()里有 MessageBox,当前的 WndProc()会暂时停止在 MessageBox,直到 MessageBox 返回才继 续执行后面的语句!!
{
TranslateMessage(&msg);
if(msg.message ==WM_COMMAND) WinExec("cmd /k
TranslateMessage()ok",SW_SHOW);
//加上这句
DispatchMessage(&msg);
if(msg.message ==WM_COMMAND) WinExec("cmd /k
while (GetMessage(&msg, NULL, 0, 0)) {
if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
TranslateMessage(&msg); DispatchMessage(&msg); } } 3.在 WndProc()里,对各个消息进行处理!!
TranslateMessage: 将 msg 结构传给 Windows,进行一些转换,比如 A 键按下, 转 换 成 WM_CHAR 消 息 等 。 TranslateMessage 是 对 一 些 键 盘 事 件 做 预 处 理 。 TranslateMessage 是翻译需要翻译的消息。 翻译消息不是简单的转换,一个消息被翻 译后,可能会产生几个消息。
出来了
发现,点菜单的 ABOUT..., WinExec(显示 TranslateMessage()ok)执行,显示出 MessageBox;MessageBox 关闭后,WinExec(显示 DispatchMessage()ok)才会执行。 OK,符合正常的消息处理原则,即 DispatchMessage()要等到 WndProc()执行完才会返 回。
如果 MessageBox 出现,这时一个 WM_PAINT 出现了,则会执行一个新的 WndProc()。 即 WndProc()并行出现了!!线程只有一个,但 WndProc()可以出现多个!
用 ABOUT 对话框代替 MessageBox,情况也是一样!ABOUT 对话框出现时,父窗口(即 主程序)点不出来,但父窗口 WM_PAINT 能正常运行!!!
重新开始试: 1. 点菜单的 ABOUT..., WinExec(显示 TranslateMessage()ok)执行,显示出第一 个 MessageBox。 2. 再到主窗,点菜单的 ABOUT..., 显示出第二个 MessageBox,但 WinExec(显示 TranslateMessage()ok)没有执行!! 3. 关闭第一个 MessageBox,WinExec(显示 DispatchMessage()ok)仍没有执行。 4. 最后,关闭第二个 MessageBox,DispatchMessage()ok)才执行。
结论: 对话框、消息框等子窗口是用自已默认的消息循环,而不是重入到父窗的消息循
环!! 主窗阻塞了,第 1 个子窗负责消息循环,调用线程的消息响应函数(包括主窗、第
1 个子窗的消息响应函数); 第 1 个子窗阻塞了,第 2 个子窗负责消息循环,调用线程的消息响应函数(包括主
窗、第 1 个子窗、第 2 个字窗的消息响应函数);。。。 子窗是一级一级阻塞下去的,后一个子窗关闭了,才能使前一个子窗的消息响应函
那么还要消息循环干什么,windows 直接把消息发给窗口不就可以了吗? 因为你要在消息循环里把 KEY_DOWN 和 KEY_UP 组合成 WM_CHAR,还可以直接屏蔽掉 许多对你来说无用的消息,加快速度。
GetMessage: 从线程的消息队列取出一个消息 。GetMessage 是从系统为每个 应用程序自动分配的消息对列的头部得到一个消息。
DispatchMessage()ok",SW_SHOW);
//加上这句
}
}
echo echo
在 WndProc()中: case IDM_ABOUT: //DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); //
这句屏蔽掉 MessageBox(NULL,"in about","",MB_OK); /->第一个消息框阻塞->第二个消息框
如果第一个消息框关闭,但第二个消息框未关闭,则第一个消息框调用的消息响应 函数仍在阻塞中,故父窗调用的消息响应函数也在阻塞中,所以继续运行不下去,而第 二个消息框仍在进行消息循环。只有第二个消息框关闭了,第一个消息框调用的消息响 应函数才会继续运行并返回,然后父窗调用的消息响应函数才会继续运行并返回!!!
即像别的文章说的,对话框和消息框会有自己的消息循环,但线程是同一个线程, 所以线程的所有消息会被分发处理。
三、再试下面程序,
void CUnicodewcharDlg::OnButton4()
{
SendMessage(UM_SOCK);
// UM_SOCK 为自定义消息,已经和 OnRecv 相关联
第二个消息框消息循环,收到父窗 WM_PAINT,调用父窗消息响应函数,WM_PAINT 这一部分如果没有阻塞,则消息响应函数可以马上返回。再进行下一个消息处理。所以 父窗不会因为没有刷新而失去显示,否则就显示不正常了。
消息响应函数可以同时多次进入,比如父窗调用了阻塞了,第一个消息框又调用了 阻塞了,第二个消息框又调用了。。。