之前写了一个软件用于实验室的打卡提醒,其中一个重要的功能是在关机之前提醒当天晚上是否已经打卡。之前我是在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表示Block或返回TRUE
先依次打开8个测试软件实例,按照上图编号对打开的软件按照打开顺序勾选上相应选项,然后再打开SPY++,设置对相应窗口的消息捕获,注意这个设置必须按照红字标明的顺序,至于为什么马上揭晓
按下关机后,观察发现最先打开的测试用例最先关闭,然后按照打开的顺序依次关闭,最后在第7组测试用例处停止,对,关机行为被阻止了,期间并没有MSDN描述的选择对话框弹出

合并整理日志,如下

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:True0-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_ENDSESSION1-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测评

同样,测试用例和上面一样

先打开SPY++,再依次打开8个测试软件实例,按照上图编号对打开的软件按照打开顺序勾选上相应选项,设置对相应窗口的消息捕获,注意这个设置必须按照红字标明的顺序,至于为什么马上揭晓
按下关机后,观察发现最后打开的测试用例最先关闭,然后按照打开的相反顺序依次关闭,过了一段时间后程序调到类似如下的界面(无法截图放的是一个示意图,具体请自行下载测试软件测试),达到如下界面后基本上等待5秒钟关闭一个测试用例直至系统关闭。

合并整理日志,如下

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_ENDSESSION0-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:True1-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_ENDSESSION0-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:True1-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关机消息

基本上我们截获关机消息有如下需求和解决方案
1.阻止关机
前面已经说过了,这在Win7是不行的,如果你非要说我的程序就只给XP用户使,那么你要有这个功能也可以。你需要做的是在WM_QUERYENDSESSION中1秒内返回FALSE,最好是立即返回FALSE。如果你还要弹出一个对话框选择是否关机,那么默认行为是关机,在WM_QUERYENDSESSION返回FALSE前弹出模态的MessageBox给你的用户可怜的1秒钟选择是否关机。如果你取消关机了,可以在WM_ENDSESSION中通知用户。
2.写入参数到文件
微软MSDN建议是在WM_QUERYENDSESSION中立即返回,把所有的保存操作放到WM_ENDSESSION中处理,当然不要忘了XP 1秒和Win7 5秒的Block限制。
3.提示用户一些信息
如果你是要和我的软件功能一样提醒一下用户,那么把提示消息行为放在WM_QUERYENDSESSION中处理,但是Win7中如果在你的程序之前有程序阻塞超过5秒,那么就会切换到Win7独有的关机界面,这时候就看不到提示信息了,这样怎么办呢。我们上面说过了XP的Win7的程序关机顺序是不一样的,可以使用SetProcessShutdownParameters函数将当前程序的关机顺序提前并使用ShutdownBlockReasonCreate函数创建在关机界面上的提示消息。
 

博客完整测试代码和测试日志 下载链接

笔者的实验室打卡精灵最新版本可执行文件和源代码链接,其中对关机时的提醒优化主要的方法就是提升程序的关机顺序和改在WM_QUERYENDSESSION消息中提醒

原创,转载请注明来自http://blog.csdn.net/wenzhou1219

深入windows的关机消息截获-从XP到Win7的变化相关推荐

  1. 带电插拔损坏设备原理_Win10拔U盘不用再点“安全弹出”了,XP和Win7老用户都眼馋了...

    用过U盘的人都知道,当我们拔出U盘时,需要手动点击"删除USB硬件"以保证U盘结束运行,如强行拔出,轻则损坏数据,重则U盘报废,但其实很多人都不记得就直接拔了. 不过最近微软传出好 ...

  2. Delphi中的消息截获

    Windows是一个基于消息驱动的系统,因此,在很多时候,我们需要截获一些消息然后自己进行处理.而VCL系统又有一些特定的消息.下面对我所了解的delphi环境中截获消息进行一些总结.       就 ...

  3. windows远程关机

    Windows远程关机和shutdown命令双保服务器重启 文章分类:操作系统 我们在进行服务器远程维护时,经常需要进行远程关机.重启等操作,但是经常由于进程的异常退出导致服务器的出现假死现象,无法正 ...

  4. [置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)

    [置顶] [置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用) 2012-08-20 15:04 673人阅读 评论(1) 收藏 ...

  5. 如何跳过等待更新,让Windows直接关机

    Windows 默认会在关机时自动安装被挂起的 Windows Update 更新.微软的出发点是好的,在大家工作和游戏时尽量不进行干扰,在关机时来打补丁.但有没想过,这种默认设定在很多时候也会带来麻 ...

  6. windows主要鼠标消息

    windows主要鼠标消息 WM_LBUTTONDOWN 鼠标停留在客户区,同时鼠标左键按下 WM_LBUTTONUP   鼠标左键释放 WM_RBUTTONDOWN   鼠标停留在客户区,邮件按下 ...

  7. java语句电脑定时关机_月光软件站 - 编程文档 - Java - windows定时关机程序

    应网友yangxjn需要写的一个windows定时关机程序 . /** * Created by IntelliJ IDEA. * autor:cofbean * Date: 2004-3-10 * ...

  8. php控制windows系统关机,window_winXP系统设置一键关机的两种方法,windows系统关机需要三步,对我 - phpStudy...

    winXP系统设置一键关机的两种方法 windows系统关机需要三步,对我这样的懒人来说实在不方便.在网络上寻找了许多方法,最后用了一个.现在介绍给有需要的人.关机方法是鼠标一点关机或热键关机. 创建 ...

  9. Ubuntu拔掉挂载硬盘后一直卡在ubuntu的logo处以及windows强制关机会出现ubuntu出现系统恢复模式

    Q1:Ubuntu拔掉挂载硬盘后一直卡在ubuntu的logo处 A1: 这可能是ubuntu硬盘检测出现问题,需要把先前设置的硬盘挂载删除掉 按ctrl+alt+F2进入终端,看有的博主说按M(如果 ...

  10. SQL Sever2012安装错误——Windows Installer错误消息:打开安装日志文件的错误的原因及解决方案

    文章目录 一.前言 二.错误信息 三.错误原因 四.解决方案 五.结语 一.前言 这个安装报错信息是我在安装SQL Sever2012时碰到的问题,百度了一下好像没有找到切实可行的方案,正好在此记录一 ...

最新文章

  1. dhcp配置(个人)
  2. 英语什么意思_“你什么意思”用英语怎么说?千万不要说成“What#39;s your meaning?”...
  3. HZOJ 大佬(kat)
  4. 基于JAVA+SpringBoot+Mybatis+MYSQL的汽车租赁系统
  5. python怎么读excelsheet_python怎么读写excel文件
  6. python网络编程基础知识_python网络编程基础
  7. 规划风险应对-规划过程组
  8. 知网摘要作者信息爬取和搜狗微信、搜狗新闻的爬虫
  9. 内外边距问题(清除、合并、塌陷)
  10. 微信公众平台接口程序语音天气
  11. Jlink v9仿真器PCB原理图自动升级固件
  12. [线段树or笛卡尔树+简单KMP]poj4005 or hdu4125 Moles
  13. SAP BTE 增强 物料主数据变更
  14. 咸鱼前端—CSS字体外观
  15. excel中怎么显示数字/英文时间
  16. testjs插件类库组织与管理
  17. 计算机是如何执行程序的(转)
  18. 我的项目经理培训论文
  19. 液晶屏 LCD12864 / LCD12232 串行 / 并行接口驱动
  20. MySql GRANT IDENTIFIED BY 语句出错

热门文章

  1. centos8同步时间安装时间校准服务
  2. 性能测试职业发展方向
  3. 物联网+安防在智慧社区建设中的发展与深度应用
  4. Win7---保护眼睛的电脑窗口颜色设置
  5. TeamViewer被检测为商用后的合理申诉
  6. oracle性能调优之--Oracle 10g AWR 配置
  7. 如何在手机上查银行卡号?进来手把手教你!
  8. 手机屏幕的色彩偏离度(ΔE)(也就是常说的色准)
  9. scp远程拷贝命令及not a regular file 解决方案
  10. LANTENNA:通过以太网电缆泄露,从物理隔离网络中窃取数据