Windows编程启示录 计时框的困惑

renzhewh 2011-04-09 03:43:38


关于《Windows编程启示录》中 8.15 一节:计时框改进版本的困惑

发现不仅计时消息框关闭了,主程序也结束了!

调试时发现TimedMessageBox中的PeekMessage调用失败,它并没有
成功的移除WM_QUIT,这是为什么呢?


我猜想的控制流是:WM_QUIT首先被发送给MessageBox中的模态消息循环,
后者处理了这个消息(销毁自己),并向所属线程的消息队列中重发了这个消
息,紧接着MessageBox返回,在TimedMessageBox中通过PeekMessage试图移除
这个消息(不知道为什么会失败?),然后对话框在模态消息循环中接收到了
WM_QUIT,从而程序结束…

...全文
315 32 打赏 收藏 转发到动态 举报
写回复
用AI写文章
32 条回复
切换为时间正序
请发表友善的回复…
发表回复
Lactoferrin 2011-04-11
  • 打赏
  • 举报
回复
现在没法看
renzhewh 2011-04-11
  • 打赏
  • 举报
回复
一直开着,你看到了吗? 那把细节发下吧
Lactoferrin 2011-04-11
  • 打赏
  • 举报
回复
一直把spy++开着看
renzhewh 2011-04-11
  • 打赏
  • 举报
回复
关于计时框

我在 PeekMessage 后使用 GetQueueStatus(QS_ALLEVENTS),返回值的高序部分为 0x0008,即为
QS_POSTMESSAGE(投递消息)

后使用 Spy++,然而检测时没有发现有 ID > 0xc000 的消息?
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
[Quote=引用 2 楼 renzhewh 的回复:]

C/C++ code

这是另一个让我困惑的地方

在《Windows 程序设计》中文第五版 3.1.1 中提到:
【windows 向应用程序发送了一条消息,我(这个‘我’自然是书作者了)希望你能反复品味这句话,它到底
有什么含义?这里我们正在讨论的是程序代码而非电报系统,那么操作系统是如何将消息传递给应用程序的?
当我提到“ windows 向应用程序发送了一条消息”这句话时,我其实是说 ……
[/Quote]
这是户进程调用了窗口过程,但是DispatchMessage是windows的代码,所以也可以说是Windows 调用了窗口过程
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
user32中有个MessageBoxTimeoutA,MessageBoxTimeoutW就有这个功能
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
你把DispatchMessageW到NtUserDispatchMessage的流程拿来看一下,找了半天没找到
辰岡墨竹 2011-04-10
  • 打赏
  • 举报
回复
NtUserDispatchMessage就是Win32K.SYS里的,到了Ring0。
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
DispatchMessage哪里有Int 2eh或者sysenter,我没看到
辰岡墨竹 2011-04-10
  • 打赏
  • 举报
回复
DispatchMessage怎么不进入内核模式?它里面就有Int 2eh或者sysenter进入核心的指令。

http://blogs.msdn.com/b/oldnewthing/archive/2005/03/04/385100.aspx

Raymond的说法是你应该循环等到WM_QUIT弹出来……
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
DispatchMessage不进入内核模式,仅在用户模式办事
就算进入了内核模式,执行代码的还是调用DispatchMessage的进程,所以可以说是用户进程调用了窗口过程

应该是这样,但是有什么好的解决方案呢?

在超时的处理中,如果使用循环直到等到 WM_QUIT,那么被该循环丢掉的消息该怎么处理呢?

是否由此可以说 这种方法实现计时消息框 不是很好呢?

你可以尝试发送WM_CLOSE,或者使用MessageBoxTimeout
辰岡墨竹 2011-04-10
  • 打赏
  • 举报
回复
回9楼,
你的程序消息循环Dispatch时不是你的程序去获得注册的窗口过程的(并不是你想的那样),而是直接把消息传递给内核,由内核反过来去调用的你注册的窗口过程,这样更加直接。而且Windows可以更加灵活地监控你的程序执行进度,必要时不再给你的程序分配CPU(没有消息要处理时)。
而且KEY_DOWN和KEY_UP需要被组合成WM_CHAR。某些窗口组件可能会在消息队列里放入一些非标准的内部消息(比如你获得的那些神奇消息)。而且计时器消息是没有绑定窗口的,而是有对应的回调函数(不能CallWindowProc)。所以需要DispatchMessage交给内核来做。
renzhewh 2011-04-10
  • 打赏
  • 举报
回复
此外,那些 ID > 0xc000 的消息又是什么呢?
renzhewh 2011-04-10
  • 打赏
  • 举报
回复
应该是这样,但是有什么好的解决方案呢?

在超时的处理中,如果使用循环直到等到 WM_QUIT,那么被该循环丢掉的消息该怎么处理呢?

是否由此可以说 这种方法实现计时消息框 不是很好呢?
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
等一下,我觉得原因是这样,PeekMessage取回的是队列消息,有先后顺序的,如果排在最前的是消息A,你PeekMessage的范围中没有消息A,那就说找不到消息,它总是取回排在最前的消息
renzhewh 2011-04-10
  • 打赏
  • 举报
回复
写得不对
依次获取的消息 ID 应该是:0xc0df,0xc0ea,0xc0df,0x0012

renzhewh 2011-04-10
  • 打赏
  • 举报
回复

我只是重复的写了 2 次 PeekMessage,一次是 0xc0df,一次是 0xc0ea

加多次数后,如下:
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
PeekMessage(&msg, NULL, WM_QUIT, WM_QUIT, PM_REMOVE);

这样才可以,依次获取的消息 ID 是:0xc0df,0xc0a,0xcodf,0x0012

使用 do{PeekMessage(&msg,0,0,0,1);}while(msg.message!=0x12) 自然也可以,不过
也只能限于这种情形的调试了
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
都不一样?
renzhewh 2011-04-10
  • 打赏
  • 举报
回复
调试信息,供参考

用多条 PeekMessage(&msg, NULL, 0, 0, PM_REMOVE);
发现有多个 ID > 0xc0000 的消息
Lactoferrin 2011-04-10
  • 打赏
  • 举报
回复
[Quote=引用 14 楼 renzhewh 的回复:]
To Lactoferrin

在 《Windows 编程启示录》中提到,WM_QUIT 不会受到过滤器的影响,我想作者这样做应该只
是为了不获取其他消息

按照你说的,我这里还是无法获得 WM_QUIT,其次这个‘神奇消息’的数值好像还不是固定的,最后
ID 大于 0xc000 应该是被应用程序使用的字符串消息没有见到什么文献提到在这种情况下会有这个消息

怪!
……
[/Quote]
你这里用的是什么,照你的应用
PeekMessage(&msg, NULL, 0xC0C1,0xC0C1, PM_REMOVE);
或者你用循环把0-65535都扫一遍


反正do{PeekMessage(&msg,0,0,0,1);}while(msg.message!=0x12)是可以得到WM_QUIT的
加载更多回复(10)

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧