深入windows的关机消息截获-从XP到Win7的变化
之前写了一个软件用于实验室的打卡提醒,其中一个重要的功能是在关机之前提醒当天晚上是否已经打卡。之前我是在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
深入windows的关机消息截获-从XP到Win7的变化的更多相关文章
- 深入windows的关机消息截获-从XP到Win7的变化(在XP中程序可以阻止关机,但是在Win7中程序无法阻止关机,可Block的时间从1秒调到了5秒) good
之前写了一个软件用于实验室的打卡提醒,其中一个重要的功能是在关机之前提醒当天晚上是否已经打卡.之前我是在WM_ENDSESSION中弹出一个模态对话框来提醒,在XP中基本工作正常,在Win7中大多数时 ...
- 关于 OnCloseQuery: 顺序、不能关机等(所有的windows的广播消息都是逐窗口传递的)——如果一个窗体的OnCloseQuery事件中如果写了代码那么WM_QUERYENDSESSION消息就传不过去了msg.result会返回0,关机事件也就停止了
系统关闭窗体的事件顺序为: OnCloseQuery ----> OnClose ----> OnDestroy 下面的代码说明问题: unit Unit3; interface uses ...
- 黑客编程教程(六)Windows的关机和重起
第六节 Windows的关机和重起 很多木马都有远程关机功能,但这并不是一个很好的功能.不过对于入侵服务器,有时需要重起服务器.其实对于关机和重起,只需要调用几个 API函数即可实现. 对于WIN9X ...
- C#实现控制Windows系统关机、重启和注销的方法:
shutdown命令的参数: shutdown.exe -s:关机shutdown.exe -r:关机并重启shutdown.exe -l:注销当前用户 shutdown.exe -s -t 时间:设 ...
- Delphi中window消息截获的实现方式(1)
近来笔者在一个项目中需要实现一个功能:模仿弹出菜单的隐藏方式,即鼠标在窗口的非PanelA区域点击时,使得PanelA隐藏. 经过思考,笔者想到通过处理鼠标的点击事件来实现相应功能.但是,究竟由谁 ...
- windows远程关机重启
windows远程关机 http://lsscto.blog.51cto.com/779396/245681 shutdown http://baike.baidu.com/view/596875.h ...
- Delphi中的消息截获(六种方法:Hook,SubClass,Override WndProc,Message Handler,RTTI,Form1.WindowProc:=@myfun)good
Windows是一个基于消息驱动的系统,因此,在很多时候,我们需要截获一些消息然后自己进行处理.而VCL系统又有一些特定的消息.下面对我所了解的delphi环境中截获消息进行一些总结. 就个 ...
- C#实现控制Windows系统关机、重启和注销的方法
shutdown命令的参数: shutdown.exe -s:关机shutdown.exe -r:关机并重启shutdown.exe -l:注销当前用户 shutdown.exe -s -t 时间:设 ...
- 再谈Delphi关机消息拦截 -- 之控制台程序 SetConsoleCtrlHandler(控制台使用回调函数拦截,比较有意思)
这里补充一下第一篇文章中提到的拦截关机消息 Delphi消息拦截:http://blog.csdn.net/cwpoint/archive/2011/04/05/6302314.aspx 下面我再介绍 ...
随机推荐
- CSS样式表基础知识、样式表的分类及选择器
一.CSS基本概念: CSS(Cascading Style Sheet,叠层样式表),作用是美化HTML网页. /*注释区域*/ 此为注释语法 二.样式表的分类 1.内联样式表(和html联合 ...
- 我常用的iphone开发学习网站[原创]
引用地址:http://www.cnblogs.com/fuleying/archive/2011/08/13/2137032.html Google 翻译 Box2d 托德的Box2D的教程! Bo ...
- Android 开发技巧
1, ActionBar.setTitle() 的参数是 CharSequence,可以用SpannableString的,颜色字形随你
- Yii2 数据操作DAO
参考: http://www.yiiframework.com/doc/guide/1.1/zh_cn/database.dao http://blog.csdn.net/hzqghost/artic ...
- awk参数详解
wk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 awk处理过程: 依次对每一行进行处理,然后输出 awk命令形式: awk [-F| ...
- VCC、VDD、VEE、VSS的区别
电路设计以及PCB制作中,经常碰见电源符号:VCC. VDD.VEE.VSS,他们具有什么样的关系那? 一.解释 VCC:C=circuit 表示电路的意思, 即接入电路的电压 VDD:D=devic ...
- junit参数化测试的使用方法
JUnit参数化测试的五个步骤:(1)为准备使用参数化测试的测试类指定特殊的运行器 org.junit.runners.Parameterized.(2)为测试类声明几个变量,分别用于存放期望值和测试 ...
- [置顶] IT屌丝的离职申请
各位好,很遗憾在如此关键的时刻和大家说告别.我为金三也付出了近一年的心血,几乎没怎么休过令人舒心的周末,熬了多少夜更不用说,如此的离开,请相信我也非常心痛. 尽管直到现在我的水 ...
- Swap file ".Podfile.swp" already exists!
解决Swap file ".ceshi.c.swp" already exists!问题 关于swp文件:使用vi,经常可以看到swp这个文件,那这个文件是怎么产生的呢,当你打开一 ...
- 【UVA】658 - It's not a Bug, it's a Feature!(隐式图 + 位运算)
这题直接隐式图 + 位运算暴力搜出来的,2.5s险过,不是正法,做完这题做的最大收获就是学会了一些位运算的处理方式. 1.将s中二进制第k位变成0的处理方式: s = s & (~(1 < ...