正确处理Windows电源事件

摘要:
本文通过案例描述了Windows*环境下系统准备挂起时的状态,以及挂起操作和从挂起状态恢复操作。我们将重点研究WindowsXP*Professional操作系统上的消息传递,所提供的代码实例将用来讲解如何准备和从挂起状态恢复。本文的讨论内容面向对Windows消息收发有一定认识基础的读者。定义WM_POWERBROADCAST–通过WindowProc()函数向应用广播的消息。因此,任何必要的关闭操作都应当在收到事件时立即开始。但系统会继续发出用来处理电池和电源状态变化的事件,因此这些事件仍然可被监测到。

简介
为系统挂起与恢复而进行的应用准备步骤

曾几何时,当您正要通过应用提交或发布一些重要数据时,突然遇到一些急事需要处理,而且会耽误很长时间。当您完成任务回到电脑前时,发现电脑已经自动进入 了挂起状态,或是完全关机。您可能因此丢失了部分或全部重要数据,而这仅仅是因为应用没能在停止执行前“保存”数据。相信拥有类似经历的人不在少数。现 在,应用开发人员设计出了一种专门的应用,来帮助我们避免发生这种情况。该应用可在系统挂起或休眠之前,通过操作系统发送相应消息与事件通知用户。

本文通过案例描述了 Windows* 环境下系统准备挂起时的状态,以及挂起操作和从挂起状态恢复操作。我们将对消息和事件的发送目的进行讲解,提供一些有关用法与计时方面的信息,并给出一些 高效使用建议,助您避免潜在的数据丢失。此外,我们还会深入探讨应该通过何种类型的应用来实现对此类消息与事件的收发。我们将重点研究 Windows XP* Professional 操作系统上的消息传递,所提供的代码实例将用来讲解如何准备和从挂起状态恢复。此外,本文还提出一些建议,帮您避免挂起或是绕过当前的种种局限。本文的讨 论内容面向对 Windows 消息收发有一定认识基础的读者。
定义
WM_POWERBROADCAST – 通过 WindowProc() 函数(告知电源管理事件已经/正在运行)向应用广播的消息。
PBT_APMQUERYSUSPEND – 需要经许可才能挂起的事件
PBT_APMQUERYSUSPENDFAILED – 通知挂起请求失败的事件
PBT_APMRESUMEAUTOMATIC – 自动从挂起状态恢复时所收到的事件
PBT_APMRESUMECRITICAL – 通知从未知或不稳定状态恢复的事件
PBT_APMRESUMESUSPEND – 通知从挂起状态恢复的事件
PBT_APMSUSPEND – 系统挂起前收到的事件
推动因素
应用程序的开发是一项技巧性很强的工作。随着移动环境的到来,这种情况也会变得日益凸显。首先,我们 需要确定哪些应用可能会因系统挂起而丢失数据,哪些应用则不会。需要考虑的应用包括:任何会受到操作系统环境变化影响的应用,如网络连接、USB 连接或 Firewire* 连接,任何操作完成前不能中断的应用以及任何无需用户交互就能在显示器上显示信息的应用。

假如应用正在使用网络中的某个文件时系统进入挂起状态,将会出现何种情况?此时,即使执行了恢复操作,之前的网络连接也不再可用,除非应用能预先“意识” 到您将遭遇困境。如果情况发生在通过 Firewire 或 USB 连接刻录 CD/DVD 盘片时,您将如何应对?如果真是这样,那么很不幸,您的盘片只能当杯垫用了。假如您在向一位重要客户进行演示,中途停下来进行讲解或问答时却出现系统挂 起、显示中止的尴尬局面?这时,您不得不花费宝贵的时间来重启电脑,打开演示并找到此前位置,继续进行演示。由此可见,防止应用挂起是多么的重要。

众多事例都证明了一个观点:开发一种依靠系统消息来防范挂起的应用是很有必要的。当系统无法从挂起状态恢复、需要重新启动时,能够对电源消息做出回应的应 用将显得更为灵活和可靠。通过创建备份文件,您可更轻松地检索挂起前存储的数据,更省力实现挂起恢复。
系统挂起
系统挂起进程主要用于节省移动设备的能耗或在移动某一设备前关闭硬盘。该进程一般会关联到用户设置, 用来关闭特定时间内未被使用的设备。如果电源设置适当,还可通过关闭笔记本电脑顶盖来调用系统挂起进程。为了展示与系统挂起相关的消息模式,我们以远程控 制方式连接到了测试系统,并在测试系统上调用 Spy++,用来检查和捕捉由测试系统广播的 WM_POWERBROADCAST 消息和事件。通常,应用收发的消息模式如下:

S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMQUERYSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001] SWM_POWERBROADCAST (long)dwPowerEvent:PBT_APMSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]

(注:以字母“S”开头的命令行表示消息需要通过 SendMessage() 函数发送。而以字母“R”开头的命令行表示来自应用的消息返回值。) 上述模式表明:系统向应用发送一个包含 PBT_APMQUERYSUSPEND 事件的 WM_POWERBROADCAST 消息并请求应用许可,如果得到允许则挂起系统。该消息和事件会发送给系统内当前运行的所有应用、线程及进程。在所有事件中,该事件通常会首先引起系统挂 起。收到消息后,应用应当在返回前做好关闭准备。这些准备工作根据不同应用而异,但应当包含诸如将数据库表存储到硬盘、保存文件到硬盘、释放内存或共享资 源、断开网络连接或关闭任何其它有利于确保应用安全退出的任务。一般情况下,系统最多能从应用的消息队列中提取 20 秒长的消息。因此,任何必要的关闭操作都应当在收到事件时立即开始。本案例中,应用返回值为“TRUE(真)”,表示可以继续执行挂起。

系统挂起前发送的消息为带有 PBT_SPMSUSPEND 事件的 WM_POWERBROADCAST。而返回值“TRUE(真)”由应用返回。
拒绝挂起请求
如果应用不准许或“不希望”系统执行挂起,就会通过某种方式通知系统请求已被应用拒绝。为此,应用会 在收到 PBT_APMQUERYSUSPEND 事件时返回 BROADCAST_QUERY_DENY 值。这时系统就会“知道”:某一应用或进程不能或“不允许”挂起操作。在应用拒绝挂起的情况下,消息模式如下:

S WM_POWERBROADCAST (long) dwPowerEvent:PBT_APMQUERYSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:424D5144]
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMQUERYSUSPENDFAILED
请注意,在该案例中,lResult 中的应用返回值为 424D5144,即 BROADCAST_QUERY_DENY 的值。随后,系统发出 PBT_APMQUERYSUSPENDFAILED 事件,通知所有应用:挂起请求失败,继续执行应用内的正常操作。

此外,我们也可以使用 SetThreadExecutionState() 函数防止系统挂起。该函数用来向系统发出其正在被使用的通知,并完全防止系统发送用来执行挂起的 WM_POWERBROADCAST 消息和事件(正如我们的测试所表明的那样)。但系统会继续发出用来处理电池和电源状态变化的事件,因此这些事件仍然可被监测到。有 3 个标记与此函数存在关联:ES_SYSTEM_REQUIRED——表明某些操作正在执行;ES_DISPLAY_REQUIRED——表明某些操作需要 进行显示;ES_CONTINUOUS——通知系统在发生变化前保持伴随状态。我们建议:像传真服务器、应答机、备份代理以及网络管理这样的应用都应当使 用 ES_SYSTEM_REQUIRED,而多媒体应用(如视频播放器和演示应用等)应当使用 ES_DISPLAY_REQUIRED。如未使用 ES_CONTINUOUS,空闲计时器将被完全重置,因此需要定期调用该函数来重置计时器。但也要注意,该函数不会阻止因关闭笔记本电脑顶盖造成的系统 挂起。从根本上阻止系统挂起的唯一办法就是拒绝上文中提到的 PBT_APMQUERYSUSPEND 事件。此外,该函数不会一直阻止屏保的运行。另外还有许多其它方式也可以阻止挂起,如事先定义好一个时间值,然后用 SystemParametersInfo() 函数来查询和重置屏保超时数值。
从挂起状态恢复
对应用而言,离开挂起状态并继续执行操作与进入挂起状态这一系统行为同等重要,因此应用开发人员在处 理进程执行中收到消息时应尤其注意。恢复内存、磁盘状态以及数据库表这些案例仅代表了应用中的部分元素,而应用离开挂起状态时还需要进行刷新和重新配置。 如果这些元素未处于正常状态,那么即使是正常的应用行为也会造成数据的破坏和丢失。在挂起过程中,WM_POWERBROADCAST 消息用于向应用发出正在/已经完成恢复操作的告警。一般来讲,下列消息和事件都会由操作系统发出:

S WM_POWERBROADCAST (long)dwPowerEvent:0012
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMRESUMESUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
第一个事件为 0x12,对应 PBT_APMRESUMEAUTOMATIC。该事件仅用于向应用发出正在执行自动恢复操作的通知。通常情况下,该事件无需回应,但也有一个例外——这 一点会在下文中讲到,设计应用时要注意这个问题。下面要发出的事件为 PBT_APMRESUMESUSPEND。只有在执行挂起进程的过程中发送 PBT_APMSUSPEND 的情况下,该事件才会被发出。这表明:系统已经安全完成了恢复操作,应用可以继续执行。如果应用在挂起时释放内存、数据库表或其它重要信息,开发人员就必 须对这些应用内的运行元素重新进行初始化或分配。上文已经提到,使应用保持正常运行状态十分重要。

其它能够收到的恢复事件包括:PBT_APMQUERYSUSPENDFAILED 和 PBT_APMRESUMECRITICAL。上文已经说过,如果某些其它进程已经拒绝了系统发出的挂起请求,系统就会收到表明应用可以继续执行正常操作 的PBT_APMQUERYSUSPENDFAILED 事件。PBT_APMRESUMECRITICAL 会在部分或全部应用没有收到 PBT_APMSUSPEND 事件(如在电池耗尽后的情况)时发出。消息是非常重要的,因为如未收到消息,那么先前可用的资源或数据可能会变得无法使用。而对于异常脆弱的网络连接,应 用更应提前保存位于网络上的任何文件或数据。总之,任何应用都应当在收到这一事件时恢复到最佳状态,保证最理想的效能。
休眠
系统关闭时,休眠功能会完全保留系统状态,以便在电源重新接通时系统能够恢复到休眠前的状态。但是, 当系统由挂起状态转入休眠状态,然后再回到先前状态时,消息模式中会出现一件十分有趣的反常现象。下面的例子便描述了该模式下的异常状态:

即将挂起
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMQUERYSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
即将休眠
S WM_POWERBROADCAST (long)dwPowerEvent:0012
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMQUERYSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMSUSPEND
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
按下开机按钮
S WM_POWERBROADCAST (long)dwPowerEvent:0012
R WM_POWERBROADCAST fSucceeded:True [lResult:00000001]
S WM_POWERBROADCAST (long)dwPowerEvent:0012
系统进入休眠状态时,事件顺序发生了变化,当我们再次启动系统后,接收到了 PBT_APMAUTOMATICRESUE,0x12 事件。与正常顺序比较后我们发现:PBT_APMRESUMESUSPEND 事件不见了,这表明系统执行了恢复操作。测试后我们得出结论:有些情况下,只能接收到一条 0x12 代码;而有些情况下则会收到两条。无论怎样测试,从休眠状态恢复时我们都没有收到 PBT_APMRESUMESUSPEND 事件,即使文档记录中提示该事件将发出的情况下,我们也未收到。也许我们需要在 PBT_APMRESUMESUSPEND 和 PBT_APMAUTOMATICRESUME 事件之间进行协调,以确保应用能在挂起操作之后保持正常的运行状态。
代码实例
为便于读者透彻了解如何处理与挂起和恢复操作相关的消息和事件,我们特举如下范例说明:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,

WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;

switch (message)
{
.
.
.
case WM_POWERBROADCAST:

switch (wParam)
{
case PBT_APMQUERYSUSPEND:
PrepToSuspend(TRUE);
return (TRUE);
case PBT_APMQUERYSUSPENDFAILED:
ReInitVars();
break;
case PBT_APMRESUMESUSPEND:
ReInitVars();
break;
case PBT_APMSUSPEND:
break;
case PBT_APMRESUMECRITICAL:
ReInitVarsCritical();
break;
case PBT_APMBATTERYLOW:
MessageBox(hWnd,”Battery is Critical”,”Low Battery”,MB_OK);
break;
case PBT_APMPOWERSTATUSCHANGE:
AdvisePowerChange();
Break;
case PBT_APMOEMEVENT:
break;
case PBT_APMRESUMEAUTOMATIC:
break;
}
.
.
.
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}

这个方法可以处理每个与 WM_POWERBROADCAST 消息存在关联的事件,但绝对不是唯一的方法。请注意,在收到 PBT_APMQUERYSUSPEND 事件并返回 TRUE(真)后,应用对 PrepToSuspend(TRUE) 的调用也随之发生。如果应用需要拒绝挂起请求,只需返回一个 BROADCAST_QUERY_DENY,而不必像实例中那样调用函数。还需注意的是,每个非关键恢复相关消息都会调用 ReInitVars() 函数,而关键恢复事件则会调用 ReInitVarsCritical() 函数。函数内容的差异可以通过一个更为强大且面向关键恢复的初始化过程(前文已经提到)反映出来。

上面的实例中还列出了本文并未提及的 3 个事件。PBT_APMOEMEVENT 并不是一个统一事件,OEM 厂商会根据自己的判断来尝试捕捉各自事件。多数情况下,该事件无需回应。如果系统标出了这一状态,PBT_APMBATTERYLOW 就会被收到。必要时还会采取其它适当行动,而不仅仅是通知用户电池电量不足。PBT_POWERSTATUSCHANGE 属于事件,由应用处理。该事件会标示出机器中电源状态的变化,并及时报告电池电量信息及其它应用所需的重要数据。具体细节还很多,就留待各位读者自己去发 现吧。
结论
每次审视应用的新功能、确定其是否与特定产品相关时,我们都会提出“我们为什么要这样编写应用?”这 个老问题。在解决挂起这个问题上,随着越来越多的人选择购买笔记本电脑并将其作为家用和办公环境中的主要系统,如何避免因挂起导致的数据丢失便成了摆在应 用开发人员面前的一个日益紧迫的问题。能够自由的挂起或恢复至运行状态、将错误和问题降至历史最低点、像欣赏艺术那样体验应用挂起——这就是用户心中的理 想应用。需要依赖网络中的文件或内容,需要在无需用户交互的情况下确保长时间的显示和运行,需要能够捕捉用户输入用于存储或日后调用的信息,需要存储大量 数据等等——只有符合这些标准的应用才能可靠地处理此类消息和事件。软件架构师和战略家能够设计出更为可靠、更加优秀的应用,帮助人们应对移动办公和生活 方式带来的挑战。

如今,要满足用户对移动计算的需求,就必须对软件需求进行一次重大改造。而操作系统可以利用 WM_POWERBROADCAST 消息来标示系统运行过程中即将出现的各种变化。众所周知,挂起功能可以节约电池能耗,今后势必将给应用带来更为深远的影响。而应用设计也应更加重视能耗问 题,想方设法延长电池的使用时间。通过合理安排消息与事件,我们终将实现降低应用能耗的目标。

http://blog.csdn.net/harbinzju/article/details/5844791

免责声明:文章转载自《正确处理Windows电源事件》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇实现图片向上不停的无限滚动效果简单代码转:HTML获取屏幕、浏览器、页面的高度宽度下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

装系统那些事儿-1-电脑的启动流程

如果对使用电脑遇到的问题做一个统计的话,我想装系统一定会是前十。笔者使用电脑这么多年,风风雨雨中自己或帮别人装了各种系统几十上百次。不管操作系统怎么更新换代,不管是DOS、Windows、Linux,不管是图形界面还是命令行界面,大家都面临一个基础性问题——装系统。 所以,我决定在此将装系统的那些事儿汇总一下,不管你是安装什么系统或遇到什么问题或解决了问题...

adb 环境配置 常用命令 [MD]

markdown 格式 博文地址 我的GitHub 我的博客 我的微信 我的邮箱 baiqiantao baiqiantao bqt20094 baiqiantao@sina.com adb简介 ADB,即 Android Debug Bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。...

将chrome浏览器的默认背景颜色修改为浅绿色,以减缓长时间看电脑的眼睛不舒服的问题

修改chrome文件夹中的Custom.css, 此文件里面默认内容是空的。 在其中添加下面这段代码: 你也可以选择自己的喜欢的颜色, 前提是你知道你想要更改的颜色的十六进制颜色值, 例如:#CCEBCC。 保存之后, chrome浏览器立即生效。 ubuntu下, Custom.css在根目录中.config/google-chrome/Defaul...

大数据是什么

大数据是什么 大数据本身是一个抽象的概念。从一般意义上讲,大数据是指无法在有限时间内用常规软件工具对其进行获取、存储、管理和处理的数据集合。 目前,业界对大数据还没有一个统一的定义,但是大家普遍认为,大数据具备 Volume、Velocity、Variety 和 Value 四个特征,简称“4V”,即数据体量巨大、数据速度快、数据类型繁多和数据价值密度低,...

VMware 安装Linux系统

VMware 增加Linux系统 1、启动VMware,进入主界面 2、点击“创建新的虚拟机”,进入创建虚拟机向导界面,建议初学者选择“典型(推荐)” 3、点击“下一步”按钮,进入“安装客户机操作系统”界面选择“安装来源”,建议初学者选择第三项,创建空白硬盘的虚拟机 如果有一定经验的话,可以选择第二项,通过“浏览”按钮选择我们Linux系统的映像文...

windows xp/7/8/8.1/10安全模式详解和系统修复讲解

如果你的电脑因为各种原因(强关电脑等原因导致的电脑蓝屏,或者引导文件受损等)开不了机,进不了电脑桌面,那么就可以看看我这篇文章了。 先贴上百度百科,说得挺好的。最下面有我贴的图片操作过程详解。 百度百科: 安全模式是Windows操作系统中的一种特殊模式,经常使用电脑的朋友肯定不会感到陌生,在安全模式下用户可以轻松地修复系统的一些错误,起到事半功倍的效果。...