« 动态字体的贴图管理 | 返回首页 | 树结构的一点想法 »

WM_CREATE 引起的 bug 一则

今天在维护一个 Windows 程序时,发现一个 bug ,记录一下。

这是一个简单的 Windows 程序,在注册给窗口的 WinProc 回调函数中处理了 WM_CREATEWM_PAINT WM_TIMER 等消息。

bug 的现象是,WM_CREATE 的流程没有走完就开始处理 WM_TIMER 等消息了。表现起来仿佛 WinProc 被重入了。

仔细排查后发现,不知道什么奇怪的原因,我的 Win7 系统在处理 WM_CREATE 消息时,默认捕获了异常。导致消息处理的流程没有走完,但进程却没有崩溃,窗口也被正确创建出来了。然后这个窗口可以继续接收 WM_TIMER 等消息。

我在不同的机器上测试了一下,确认是 Windows 的问题。貌似过去没有碰到过。目前我用的是 Windows 7 的 64 位版本,使用 mingw32 生成的 32bit 程序。

有兴趣的同学可以一试,在

WinProc 里加几行:

case  WM_CREATE: {
    int *p = NULL;
    *p = 0;
    break;
}

这个非法地址写指令不会让进程崩溃。

google 了一下,似乎没有人反应类似问题。

Comments

这个问题还真是很多人都遇到的

@dpff 正解啊,正解。

stackoverflow上有人提过这个问题。http://stackoverflow.com/questions/2631452/64bit-exceptions-in-wndproc-silently-fail

@yuan
当单击窗口左上角的“关闭按钮"
应该捕获WM_SYSCOMMAND消息 ,它里面区分最小化 ,最大化, 关闭等情况


@Cloud
我想实现,当单击窗口左上角的“关闭按钮:时,退出程序。

但是怎么才能正确的捕获到 关闭按钮时,产生的消息?

我试过捕获WM_CLOSE ,WM_QUIT,WM_DESTORY,SC_CLOSE
都没有效果。

这个跟64位Windows 7有关系,在创建窗口时CreateWindow调用进入内核,内核在创建窗口后会回调用户态的WndProc,如果WndProc产生异常的话,Windows没有办法穿越内核回卷栈,所以只好将WndProc的异常吞掉了。SP1添加了group policy可以选择在这种情况下crash。

有篇英文的blog解释得很清楚:http://randomascii.wordpress.com/2012/07/05/when-even-crashing-doesnt-work/

如果你创建一个3秒中的Timer,在Timper处理过程处理10秒才退出,下一个3秒timer会在退出之前就会再次进入。这个算做重入吗?WM_TIMER的处理机制不本来就是这样的吗?

在自己的wndproc里面利用__try和__except捕获SEH异常就可以了

因为这段代码确实异常了。wm_create就跳过了。如果你开着gflags去调试这段代码。应该会断在这个位置。而不是窗口创建出

因为这段代码确实异常了。wm_create就跳过了。如果你开着gflags去调试这段代码。应该会断在这个位置。而不是窗口创建出来

有同学发邮件给我发了一小段程序。

他的系统上会崩溃。

我的 (win7 sp1 64bit) 不会。

我怀疑是 64bit windows 的问题。

上面那个是写的用VS调试时的情况,单独运行的话,没有弹出程序崩溃的提示,但窗口创建失败。

DEBUG模式和RELEASE模式都抛了异常的,程序没有捕获,只能退出。

这个是正常情况,抛出的SEH异常被windows捕获,windows会忽略这个异常,所以你如果关心这个,应该在自己的wndproc里面捕获SEH异常

Post a comment

非这个主题相关的留言请到:留言本