挂起操作

在“初识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.

LRESULT CALLBACK WindowProc(HWND   hwnd,    // handle to window

                             UINT   uMsg,    // WM_POWERBROADCAST

                             WPARAM wParam,  // power-management event

                             LPARAM lParam); // 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消息时可以阻止操作系统挂起,方法是return  BROADCAST_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,那么系统进行关机操作。