深入windows的关机消息截获-从XP到Win7的变化(在XP中程序可以阻止关机,但是在Win7中程序无法阻止关机,可Block的时间从1秒调到了5秒) good
之前写了一个软件用于实验室的打卡提醒,其中一个重要的功能是在关机之前提醒当天晚上是否已经打卡。之前我是在WM_ENDSESSION中弹出一个模态对话框来提醒,在XP中基本工作正常,在Win7中大多数时候工作正常,但是有时候会出现不提醒现象。我想这中间是不是有什么玄机,Windows的关机方案从XP到Win7到底发生了什么变化,如何进行有效的截获Windows关机消息。对此,我搜寻了MSDN和网上论坛结合自己的测评给出一个完善的描述和解决方案,如果你有类似的需求,可以参考这篇文章。
在MSDN中对于Windows关机行为的变化描述只有对比Vista和XP(这是链接),但是实际评测,显示这个描述文档对于大家有强的误导性,因为他只有部分是正确的,也不用奇怪,微软的文档错误多多,XX微软,请的实习生写的文档吗?如果你不想看这篇误导性文章,直接往下面看即可。
为了反映实际的关机行为,我写了一个小的截获软件,部分代码如下
- BOOL CEndSessionDlg::OnQueryEndSession()
- {
- // if (!CDialog::OnQueryEndSession())
- // return FALSE;
- //记录关机选项和时间
- CTime time = CTime::GetCurrentTime();
- CString csTemp;
- csTemp.Format(TEXT(".\\%d.txt"), m_hWnd);
- CFile f( csTemp, CFile::modeCreate | CFile::modeWrite );
- m_csOutput.Format(TEXT("%d-%d-%d\tWM_QUERYENDSESSION\tTIME:%d-%d-%d-%d-%d-%d\r\n"),
- m_queryBlock,
- m_returnTrue,
- m_endBlock,
- time.GetYear(),
- time.GetMonth(),
- time.GetDay(),
- time.GetHour(),
- time.GetMinute(),
- time.GetSecond());
- f.Write(m_csOutput.GetBuffer(256), m_csOutput.GetLength()*sizeof(TCHAR));
- if (m_queryBlock == TRUE)
- {
- MessageBox(TEXT("WM_QUERYENDSESSION中Block Shutdown"));
- }
- if (m_returnTrue == TRUE)
- {
- return TRUE;
- }
- else
- {
- return FALSE;
- }
- }
- void CEndSessionDlg::OnEndSession(BOOL bEnding)
- {
- //CDialog::OnEndSession(bEnding);
- //记录关机选项和时间
- CTime time = CTime::GetCurrentTime();
- CString csTemp;
- csTemp.Format(TEXT(".\\%d.txt"), m_hWnd);
- CFile f( csTemp, CFile::modeCreate | CFile::modeWrite );
- csTemp.Format(TEXT("%d-%d-%d\tWM_ENDSESSION\t\tTIME:%d-%d-%d-%d-%d-%d\r\n"),
- m_queryBlock,
- m_returnTrue,
- m_endBlock,
- time.GetYear(),
- time.GetMonth(),
- time.GetDay(),
- time.GetHour(),
- time.GetMinute(),
- time.GetSecond());
- m_csOutput += csTemp;
- f.Write(m_csOutput.GetBuffer(256), m_csOutput.GetLength()*sizeof(TCHAR));
- if (m_endBlock == TRUE)
- {
- csTemp.Format(TEXT("WM_ENDSESSION中Block Shutdown---bEnding=%d"), bEnding);
- MessageBox(csTemp);
- }
- }
软件界面如下

测试软件基本功能就是记录Winows关机时的WM_QUERYENDSESSION和WM_ENDSESSION消息的时间和关机选项到日志,根据测试软件界面上不同的选项在这两个消息中有不同的操作,阻塞关机采用MessageBox(不返回即阻塞)。
使用SPY++来捕获窗口消息并记录到日志
关于关机消息测试实例,我们参看之前那篇文章(这是链接),分别选择在WM_QUERYENDSESSION中测试Block Shutdown和Cancel Shutdown,在WM_ENDSESSION中测试Block Shutdown,穷举组合他们共有八组测试用例
XP测评
合并整理日志,如下
- 1-1-1 WM_QUERYENDSESSION TIME:2014-1-11-11-53-4
- <00001> 00060260 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 1-1-0 WM_QUERYENDSESSION TIME:2014-1-11-11-53-5
- <00001> 000102B0 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 0-1-1 WM_QUERYENDSESSION TIME:2014-1-11-11-53-6
- 0-1-1 WM_ENDSESSION TIME:2014-1-11-11-53-6
- <00001> 000402C4 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 000402C4 R .WM_QUERYENDSESSION fShutdownIsOk:True
- <00003> 000402C4 S .WM_ENDSESSION fEndSession:True
- 0-1-0 WM_QUERYENDSESSION TIME:2014-1-11-11-53-7
- 0-1-0 WM_ENDSESSION TIME:2014-1-11-11-53-7
- <00001> 00050150 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00050150 R .WM_QUERYENDSESSION fShutdownIsOk:True
- <00003> 00050150 S .WM_ENDSESSION fEndSession:True
- <00004> 00050150 R .WM_ENDSESSION
- 1-0-1 WM_QUERYENDSESSION TIME:2014-1-11-11-53-7
- <00001> 00030168 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 1-0-0 WM_QUERYENDSESSION TIME:2014-1-11-11-53-8
- <00001> 00030151 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 0-0-1 WM_QUERYENDSESSION TIME:2014-1-11-11-53-9
- 0-0-1 WM_ENDSESSION TIME:2014-1-11-11-53-9
- <00001> 00030160 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00030160 R .WM_QUERYENDSESSION fShutdownIsOk:False
- <00003> 00030160 S .WM_ENDSESSION fEndSession:False
- <00004> 00030160 R .WM_ENDSESSION //注意点击确定后才返回
- 0-0-0
- <00001> 000800BC S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 000800BC R .WM_QUERYENDSESSION fShutdownIsOk:False
- <00003> 000800BC S .WM_ENDSESSION fEndSession:False
- <00004> 000800BC R .WM_ENDSESSION
分析可得如下结论:
1.XP关机的时候依次给窗口发送WM_QUERYENDSESSION和WM_ENDSESSION消息,前一个程序结束后才给第二个发送WM_QUERYENDSESSION并不是网上有些人说的先给每个程序发送WM_QUERYENDSESSION(事实上按照MSDN描述这是Windows 95的方式)。一般是先打开的程序先关闭。
2.在WM_QUERYENDSESSION中Block Shutdown1秒钟内不返回的话,XP会强制结束它,并向下一个待关闭程序继续发送WM_QUERYENDSESSION
3.在WM_ENDSESSION中Block Shutdown1秒钟内不返回的话,XP会强制结束它,并向下一个待关闭程序继续发送WM_QUERYENDSESSION
4.在WM_QUERYENDSESSION中立即返回FALSE(至少是Block不超过1秒就返回),WM_ENDSESSION接受到的关机参数是FALSE,XP立即停止关机行为,当前返回FALSE的程序依然收到WM_ENDSESSION消息,XP不会继续向下发送WM_QUERYENDSESSION。
Win7测评
同样,测试用例和上面一样

合并整理日志,如下
- 0-0-0 WM_QUERYENDSESSION TIME:2014-1-11-11-0-55
- 0-0-0 WM_ENDSESSION TIME:2014-1-11-11-0-55
- <00001> 00020DBA S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00020DBA R .WM_QUERYENDSESSION fShutdownIsOk:False
- <00003> 00020DBA S .WM_ENDSESSION fEndSession:True
- <00004> 00020DBA R .WM_ENDSESSION
- 0-0-1 WM_QUERYENDSESSION TIME:2014-1-11-11-0-55
- 0-0-1 WM_ENDSESSION TIME:2014-1-11-11-0-55
- <00001> 00020B2C S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00020B2C R .WM_QUERYENDSESSION fShutdownIsOk:False
- <00003> 00020B2C S .WM_ENDSESSION fEndSession:True
- 1-0-0 WM_QUERYENDSESSION TIME:2014-1-11-11-1-0
- <00001> 00050CFA S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 1-0-1 WM_QUERYENDSESSION TIME:2014-1-11-11-1-5
- <00001> 00020BCA S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 0-1-0 WM_QUERYENDSESSION TIME:2014-1-11-11-1-10
- 0-1-0 WM_ENDSESSION TIME:2014-1-11-11-1-10
- <00001> 00020BE2 S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00020BE2 R .WM_QUERYENDSESSION fShutdownIsOk:True
- <00003> 00020BE2 S .WM_ENDSESSION fEndSession:True
- <00004> 00020BE2 R .WM_ENDSESSION
- 0-1-1 WM_QUERYENDSESSION TIME:2014-1-11-11-1-10
- 0-1-1 WM_ENDSESSION TIME:2014-1-11-11-1-10
- <00001> 00020C4C S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- <00002> 00020C4C R .WM_QUERYENDSESSION fShutdownIsOk:True
- <00003> 00020C4C S .WM_ENDSESSION fEndSession:True
- 1-1-0 WM_QUERYENDSESSION TIME:2014-1-11-11-1-15
- <00001> 00040C5A S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
- 1-1-1 WM_QUERYENDSESSION TIME:2014-1-11-11-1-20
- <00001> 00050C6C S .WM_QUERYENDSESSION nSource:0 (Logoff or Shutdown from Windows Security dialog)
分析可得如下结论:
1.Win7关机的时候依次给窗口发送WM_QUERYENDSESSION和WM_ENDSESSION消息,前一个程序结束后才给第二个发送WM_QUERYENDSESSION并不是网上有些人说的先给每个程序发送WM_QUERYENDSESSION(事实上按照MSDN描述这是Windows 95的方式)。一般是先打开的程序后关闭。
2.在WM_QUERYENDSESSION中Block Shutdown5秒钟内不返回的话,Win7会强制结束它,并向下一个待关闭程序继续发送WM_QUERYENDSESSION
3.在WM_ENDSESSION中Block Shutdown5秒钟内不返回的话,Win7会强制结束它,并向下一个待关闭程序继续发送WM_QUERYENDSESSION
4.在WM_QUERYENDSESSION中返回FALSE和返回TURE的效果一样,WM_ENDSESSION接受到的关机参数都是TRUE,Windows继续向下发送WM_QUERYENDSESSION。
5.一旦在5秒内没有处理完所有的程序的WM_QUERYENDSESSION和WM_ENDSESSION,Win7就会切换到“强制关机或取消”界面。
XP到Win7的关机行为变化
对比测评,可以看到XP到Win7的如下改变
1.在XP中程序可以阻止关机,但是在Win7中程序无法阻止关机。对此微软MSDN给出的描述是尽量遵循用户的行为,假设用户按下关机,那么内心是希望完成关机的,如果程序能够阻止用户关机的话,那么就是不友好的程序了,所以在Win7中干脆不允许用户程序阻止系统关机。所以这里WM_QUERYENDSESSION的返回值TURE或FALSE在Win7中是没有意义的,这只是为了兼容以前的程序,事实上不管怎样,在Win7 WM_ENDSESSION中接受到的关机信息都是TRUE。
2.那么如果是用户误操作按了关机呢?XP对此不管,Win7有个缓冲的界面(如上),允许用户取消关机,总之是越来越人性化,苦的就是开发人员。
3.对于程序来说,从XP到Win7,微软将可Block的时间从1秒调到了5秒,这允许程序做更多的收尾工作,如保存数据到文件等等。但是要明白的是一旦你的收尾工作太长,Block了超过规定的时长没有返回,系统就会Teminate程序。对此微软MSDN给出的建议,如果你的程序要保存大量数据请设置定时保存,毕竟关机时刻的行为是不可依赖的。你只能把少部分数据保存工作放在此时处理。再如果你想依靠这个消息做数据备份,那么只能说你太天真了。
有效的截获Windows关机消息
博客完整测试代码和测试日志下载链接
笔者的实验室打卡精灵最新版本可执行文件和源代码链接,其中对关机时的提醒优化主要的方法就是提升程序的关机顺序和改在WM_QUERYENDSESSION消息中提醒
原创,转载请注明来自http://blog.csdn.net/wenzhou1219
http://blog.csdn.net/wenzhou1219/article/details/18138885
http://download.csdn.net/detail/wenzhou1219/6837583
深入windows的关机消息截获-从XP到Win7的变化(在XP中程序可以阻止关机,但是在Win7中程序无法阻止关机,可Block的时间从1秒调到了5秒) good的更多相关文章
- 深入windows的关机消息截获-从XP到Win7的变化
之前写了一个软件用于实验室的打卡提醒,其中一个重要的功能是在关机之前提醒当天晚上是否已经打卡.之前我是在WM_ENDSESSION中弹出一个模态对话框来提醒,在XP中基本工作正常,在Win7中大多数时 ...
- 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了
系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...
- 通向高可扩展性之路(推特篇) ---- 一个推特用来支撑1亿5千万活跃用户、30万QPS、22MB每秒Firehose、以及5秒内推送信息的架构
原文链接:http://highscalability.com/blog/2013/7/8/the-architecture-twitter-uses-to-deal-with-150m-active ...
- Delphi中window消息截获的实现方式(2)
Delphi是Borland公司提供的一种全新的WINDOWS编程开发工具.由于它采用了具有弹性的和可重用的面向对象Pascal(object-orientedpascal)语言,并有强大的数据库引擎 ...
- Delphi中window消息截获的实现方式(1)
近来笔者在一个项目中需要实现一个功能:模仿弹出菜单的隐藏方式,即鼠标在窗口的非PanelA区域点击时,使得PanelA隐藏. 经过思考,笔者想到通过处理鼠标的点击事件来实现相应功能.但是,究竟由谁 ...
- Delphi中的消息截获(六种方法:Hook,SubClass,Override WndProc,Message Handler,RTTI,Form1.WindowProc:=@myfun)good
Windows是一个基于消息驱动的系统,因此,在很多时候,我们需要截获一些消息然后自己进行处理.而VCL系统又有一些特定的消息.下面对我所了解的delphi环境中截获消息进行一些总结. 就个 ...
- 再谈Delphi关机消息拦截 -- 之控制台程序 SetConsoleCtrlHandler(控制台使用回调函数拦截,比较有意思)
这里补充一下第一篇文章中提到的拦截关机消息 Delphi消息拦截:http://blog.csdn.net/cwpoint/archive/2011/04/05/6302314.aspx 下面我再介绍 ...
- JS将秒转换为 天-时-分-秒
记录一下,备忘.. function SecondToDate(msd) { var time =msd if (null != time && "" != tim ...
- 【笨嘴拙舌WINDOWS】键盘消息,鼠标消息
键盘消息 Windows系统无论何时只有一个窗口(可能是子窗口,也就是控件)能获得焦点. 焦点窗口通过windows消息来响应人的键盘操作,与键盘相关的常用消息罗列如下: WM_KEYDOWN 按 ...
随机推荐
- 使用Opencv中均值漂移meanShift跟踪移动目标
Mean Shift均值漂移算法是无参密度估计理论的一种,无参密度估计不需要事先知道对象的任何先验知识,完全依靠训练数据进行估计,并且可以用于任意形状的密度估计,在某一连续点处的密度函数值可由该点邻域 ...
- Function函数
一般大家都用这个写法来定义一个函数: function Name([parameters]){ functionBody }; //alert(typeof Name) // Function 当我们 ...
- 西门子S7报文解析
1.报文的基本格式 1.1 第1和第2个字节是:固定报文头03 00,这里我们就用到三种报文: a.初始化 b. 读 c.写,都是这种格式: 1.2 第3和第4个字节是:整个报文的长度: 其它部分就是 ...
- [ACM] POJ 2689 Prime Distance (筛选范围大素数)
Prime Distance Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 12811 Accepted: 3420 D ...
- QT调用VC DLL的例子(所有源码)
http://blog.csdn.net/zhuce0001/article/details/20651025 http://blog.csdn.net/zhuce0001/article/detai ...
- POJ 1988 Cube Stacking (种类并查集)
题目地址:POJ 1988 这道题的查找合并的方法都能想的到,就是一点没想到,我一直天真的以为查询的时候,输入后能立即输出,这种话在合并的时候就要所有的结点值都要算出来,可是经过路径压缩之后,没办法所 ...
- 《网络编程》ioctl 操作
概要 ioctl 功能与 fcntl 功能类似,它可以被用于描述操作的叙述字符,获取或设置属性的描述是开放式的叙事休息,但在网络编程的两个功能有关的不同类型的操作.fcntl 作.文件操作,而 ioc ...
- 在wpf datagrid中,想要根据一个条件来改变datagrid行的背景颜色
原文:在wpf datagrid中,想要根据一个条件来改变datagrid行的背景颜色 在wpf datagrid中,想要根据一个条件来改变datagrid行的背景颜色 例如根据学生的年龄来修改,年龄 ...
- IME输入法编程心得
原文:IME输入法编程心得 posted @ 2012-11-30 00:42 from [FreedomShe] 自然语言处理的输入法作业成品没有做出来,但不想再在蛋疼的Win32上面耗费时间了,整 ...
- Android备注26.Android异步任务(AsyncTask)
转载请表明出处:http://blog.csdn.net/u012637501(嵌入式_小J的天空) 一.引言 我们知道Android的UI线程主要负责处理用户的按键事件.用户触屏事件及屏幕画 ...