本文转自:http://blog.csdn.net/sad_4978/article/details/3776887感谢作者!
对于电源管理这部分功能,在做桌面软件的时候需要经常使用。尤其是在刻录光盘的时候,如果用户设置了节电方式,那么很可能导致光盘刻录失败。因此,有必要对这部分内容进行必要的了解。电源管理不单纯是操作系统的一个功能,必须有支持电源管理的主板,才能是操作系统发挥性能。
初识ACPI
说道操作系统的电源管理方式不能不介绍一下ACPI。它是操作系统实现电源管理的一个前提。
ACPI(Advanced Configuration Management)是1997年由INTEL/MICROSOFT/TOSHIBA提出的新型电源管理规范,意图是让系统而不是BIOS来全面控制电源管理,使系统更加省电。
其特点主要有:
l提供立刻开机功能,即开机后可立即恢复到上次关机时的状态。
l外设(比如:光驱)在未使用时会自动关掉电源,使用时再提供电源。
l支持热插拔。
基于上述特点又把节电分为三种方式:
l切断显示器电源,保持主机持续通电。进入挂起状态(Suspend State)后,可以通过键盘或鼠标唤醒计算机。
l操作系统把当前信息储存在内存中,只有内存等几个关键部件通电,这时计算机处在高度节电状态。进入挂起状态(Suspend State)后,可以通过键盘或鼠标唤醒计算机。唤醒后操作系统从内存中读取数据恢复到挂起前的状态。该方式又被称为挂起到内存(Save to ram or Suspend to ram)。
l操作系统将当前数据存储在硬盘上,然后自动关机。进入挂起状态(Suspend State)后,不能通过键盘或鼠标唤醒计算机,必须通过Power Key唤醒。唤醒后操作系统从硬盘中读取数据,恢复到挂起前的状态。该方式又被称为挂起到硬盘(Save to disk或Suspend to disk)。
前面对ACPI的基本内容进行了简单的描述,联系到实际可以使用ACPI可以实现以下功能:
l用户可以设定外设的开关时间。
l笔记本电脑可以在低电压的情况下进入低功耗状态,以保证重要的应用程序运行。
l操作系统可以在应用程序对时间要求不高的情况下降低时钟频率。
l操作系统可以根据外设和主板的具体需求为它分配能源。
l在无人使用计算机时可以使计算机进入休眠状态,但保证一些设备处于工作状态。
l即插即用设备在插入时能够由ACPI来控制。
对于在实际应用ACPI划分了六种状态。这六种状态对电源管理做出了准确划分。它们分别是:
S0-----正常工作状态,所有设备全部供电。
S1-----通过CPU时钟控制器将CPU关闭之。其他的部件仍然正常工作。该状态也称为POS(Power on Suspend)
S2----- CPU处于停止运作状态,总线时钟也被关闭。其余的设备仍然运转。
S3-----操作系统把当前信息储存到内存中,只有内存等几个关键部件通电。
S4-----操作系统把当前信息储存到硬盘中,这时系统主电源关闭。但硬盘仍然带电并可以被唤醒。
S5-----关机,所有设备全部断电。
操作系统的消息
挂起操作
在“初识ACPI”中对电源管理有了一个基本的了解。在软件开发中对ACPI了解到这个程度已经可以了。这里,介绍一下在Windows操作系统中操作系统是怎样进行电源管理的,并通过什么消息通知应用程序。
仔细观察Windows系统,会发现在关机时会有待机、休眠两个选项。在英文操作系统中分别是Sleep和Hibernate。如果查阅一些资料的话,可能还会看到Stand-by。那么Sleep、Stand-by和Hibernate如果区分呢?查阅了一下MSDN,没有找到更好的解释。无意间在MSDN中看到一篇早期的文章,对这三个名字做了一个说明,内容如下:
For this discussion, the term "sleep" means that the system is on standby or is in hibernation. To an application, standby and hibernation are the same. The difference occurs in how the operating system determines what gets powered down. The application does not need to provide any additional feedback for the operating system to make this determination.
我理解Sleep应该是Stand-by和Hibernate的统称,但是为什么在操作系统上显示的是Sleep,这个就说
不清楚了。好了,暂时先不去理会它们。为了继续这里把Stand-by称为待机,Hibernate称为休眠。在Windows
系统中待机对应的是S3状态,休眠对应的是S4状态。
到这里已经清楚了很多东西。接下来来了解一下Windows系统如果电源管理事件通知给应用程序的。
在MSDN中找了WM_POWERBROADCAST这样一个消息。该消息的描述:
Notifies applications that a power-management event has occurred. A window receives this message through its WindowProc function.
LRESULTCALLBACKWindowProc(HWNDhwnd,// handle to window
UINTuMsg,//WM_POWERBROADCAST
WPARAMwParam,// power-management event
LPARAMlParam); // function-specific data
通过MSDN的描述可以清楚的了解到应用程序通过重载WindowsProc这个函数就可以获得电源管理的消息。在接收到WM_POWERBROADCAST的同时,还会带给一个Event和一组Data。通过对Event和数据的分析可以得出目前操作系统处于哪种状态。这里需要注意一下,这个消息一定要通过WindowsProc函数来取得,重载PreTranslateMessage函数对于这个消息是无效的。
以Windows XP系统为基础进行描述。当Vista系统与Windows XP存在差异时,会提取差异进行描述。
当操作系统准备进入S3和S4状态时,首先会广播WM_POWERBROADCAST消息,同时会携带PBT_APMQUERYSUSPEND事件给当前正在运行的应用程序。如果应用程序不对这个事件做任何处理,表示同意挂起请求。然后操作系统会发送PBT_APMSUSPEND时间,随后操作系统马上挂起。
如果某个应用程序不希望操作系统进行挂起操作,那么当接收到PBT_APMQUERYSUSPEND消息时可以阻止操作系统挂起,方法是returnBROADCAST_QUERY_DENY;。这个操作即可以阻止系统自行发起的挂起(用户在电源管理部分进行的设定),也可以阻止用户手动发起的挂起操作。
如果应用程序想在系统进入挂起状态前进行一些处理也需要在接收到这个事件时进行处理。虽然,操作系统稍后还会发送PBT_APMSUSPEND事件过来,但是停留的时间很短。
如果应用程序在接收到PBT_APMQUERYSUSPEND事件时没有阻止系统挂起,却在PBT_APMSUSPEND事件时返回FALSE。这时,操作系统会进入挂起状态,但马上又恢复。所以,若想阻止操作系统进入挂起状态,只能在接收到PBT_APMQUERYSUSPEND事件时,进行处理。
假如,应用程序阻止操作系统挂起,返回了BROADCAST_QUERY_DENY,随后操作系统还会发送PBT_APMQUERYSUSPENDFAILED事件给应用程序,通知挂起失败。
当操作系统从挂起状态恢复时,仍然会使用WM_POWERBROADCAST消息进行广播,同时也会携带一个事件。事件的先后顺序是PBT_APMRESUMEAUTOMATIC,PBT_APMRESUMESUSPEND。由于这两个事件对应用程序的影响不大,这里就不做过多的说明了。
Vista操作系统和Windows XP存在很大的却别。在进入挂起状态前,操作系统不会广播PBT_APMQUERYSUSPEND事件,应用程序也不能阻止用户手动发起的挂起请求。操作系统从广播PBT_APMSUSPEND事件到挂起,只给应用程序预留了2秒中的处理时间。当从S3状态恢复时,只有采用键盘或鼠标唤醒系统应用程序才会收到APMRESUMEAUTOMATIC事件。这需要引起开发人员的注意。
在Vista操作系统中虽然不能阻止由用户手动发起的挂起操作,但是可以阻止由操作系统发起的挂起操作(用户在电源管理方式中进行的设定)。Windows提供了SetThreadExecutionState函数可以完成这个操作。这个函数同样适用于Windows XP操作系统。
某段程序需要阻止操作系统进入挂起时,可以使用下面代码来完成。
::SetThreadExecutionState(ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED | ES_CONTINUOUS);
当处理完成后,还要恢复操作系统的电源管理功能,使用下面代码完成。
::SetThreadExecutionState(ES_CONTINUOUS);
关机操作
当Windows系统准备关机时,会广播WM_QUERYENDSESSION消息。在这里应用程序可以做关机钱的最后处理。如果响应函数返回FALSE可以阻止操作系统关机。在MSDN中,有两个不同的描述。一个说如果在这个消息中返回非零值会接着发送WM_ENDSESSION消息,一个说返回零会发送WM_ENDSESSION消息。经过试验不论返回零还是非零在Windows XP操作系统下都会发送WM_ENDSESSION消息,
在Vista系统中如果在WM_QUERYENDSESSION消息的响应函数中返回FALSE,操作系统会弹出一个Block,然后由用户选择Yes Or No。当用户选择Yes,那么系统进行关机操作。