| January 29, 2009 9:00 PM PST | |
by Lester Memmott
In an ideal world, mobile systems would run all day without requiring the support of AC power – and with the recent launch of Intel® Centrino® Mobile Technology this is becoming closer to reality. However, in addition to the advances in hardware, software developers can now make applications power-aware by handling the WM_POWERBROADCAST message provided by the Windows* Operating System and scaling features accordingly. This whitepaper describes how to handle the WM_POWERBROADCAST message and also describes the sequence of messages for four typical cases. Additional introductory material is available from the MSDN documentation at http://msdn.microsoft.com*. MSDN, however, does not describe the expected sequence of messages in the event of AC power loss, AC power reconnect, system standby and natural battery depletion when off of AC power. These areas are explored here with a detailed analysis.
WM_POWERBROADCAST: Microsoft Windows Operating System message sent to applications to indicate system-wide power state changes.
AC Power: High voltage power supplied to a mobile system by plugging into a power outlet. This act, generally, recharges the system battery.
MSDN: Microsoft Developer Network. See http://msdn.microsoft.com*
Hardware advances have made mobile systems lighter and more energy efficient. In addition to these advances, software developers can make applications power-aware such that they enable users to work for longer periods of time before having to reconnect to recharge the system battery. For example, when on AC power, an anti-virus scanner would run full-featured, providing file scanning on all files opened and also running periodic system wide scans. When on battery power the scanner could defer the system wide scans until a later time and continue processing safely, analyzing just the open files.
Under the Windows Operating System, applications are notified of system power changes through the WM_POWERBROADCAST message. Note that the WM_POWER message is now obsolete and should be replaced with WM_POWERBROADCAST. These messages are handled through the standard message loop using GetMessage(). A sample application provided with this whitepaper shows a reference implementation for the concepts presented.
The WM_POWERBROADCAST comes with two parameters: wParam & lParam. The wParam can be a number of items which specifies the event received. The documentation for each of these is provided at MSDN as:
| Event | Meaning |
| PBT_APMBATTERYLOW | Battery power is low. |
| PBT_APMOEMEVENT | OEM-defined event occurred. |
| PBT_APMPOWERSTATUSC HANGE | Power status has changed. |
| PBT_APMQUERYSUSPEND | Request for permission to suspend. |
| PBT_APMQUERYSUSPENDFAILED | Suspension request denied. |
| PBT_APMRESUMEAUTOMATIC | Operation resuming automatically after event. |
| PBT_APMRESUMECRITICAL | Operation resuming after critical suspension. |
| PBT_APMRESUMESUSPEND | Operation resuming after suspension. |
| PBT_APMSUSPEND | System is suspending operation. |
The lParam is function specific and is not generally used.
Knowing that these messages can be received is beneficial, but it is more helpful to understand the expected sequence of these events when undergoing normal system transitions. The transitions analyzed are:
- AC Power disconnect
- AC Power reconnect
- A running system goes into standby and is powered backup
- The battery is drained from a full charge to a 0%.
The following sections show the results using a Dell Latitude* P4-M 2.4 GHz laptop. The data was captured using Spy++*, a tool installed with MSVC which allows Windows messages to be monitor for a specific running application. For each case described, capturing the data was done using the following steps:
- Launch Notepad and Spy++ (Spy++ is located under the Microsoft Visual Studio Tools, under Start -> All Programs.)
- In Spy++, Spy -> Messages
- Using the Finder Tool, drag and drop the cross-hairs from the Windows tab on the window for Notepad.
- Check the boxes for: Parent, Children, Windows of Same Thread, Windows of Same Process.
- In the Message Tab, click “Clear all”, then select WM_POWERBROADCAST.
- In the Output Tab, check the box for “Also Log in File” and provide a file name.
- Click OK.
- After running test outlined below, Press F8 (or Messages -> Stop Logging) to stop logging messages.
The data provided is the following:
- Line Number
- Message Nesting Level
- Message Code
- P = Message posted to queue with PostMessage()
- S = Message sent using SendMessage()
- R = Return value (Grouped with S codes)
- Decoded Message Parameter (always WM_POWERBROADCAST for these tests)
- lParam
- wParam
Analysis
Case 1: AC Power Disconnect
This test was run by running Spy++ as outlined above and then removi ng AC power. Items in italic are commentary added to the Spy++ output.
Test Sequence
System on AC Power
Disconnect Power Cable
<00001> 000501B4 P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
Analysis
-
The WM_POWERBROADCAST message by itself doesn’t provide enough details to know that AC power was disconnected. When the message is received, GetSystemPowerStatus() must be called to get the details.
Case 2: AC Power Connect
This test was run by starting Spy++ as outlined above and then connecting AC Power. Items in italic are commentary added to the Spy++ output.
Test Sequence
On Battery Power
Connect AC Power Cable
<00001> 000501B4 P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00002> 000501B4 P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00003> 000501B4 P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
Analysis
-
The WM_POWERBROADCAST message by itself doesn’t provide enough details to know that AC power was reconnected. When the message is received, GetSystemPowerStatus() must be called to get the details.
Case 3: Standby and Resume
This test was run by starting Spy++ as outlined above, putting the system into standby mode and then starting the system backup again. Items in italic are commentary added. The system was on AC power the whole item.
Test Sequence
Start Standby Process
<00001> 000201FA S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMQUERYSUSPEND dwData:00000001
<00002> 000201FA R WM_POWERBROADCAST fSucceeded:True (//Return true to indicate that suspend is OK.)
<00003> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00004> 000201FA S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMSUSPEND dwData:00000000
<00005> 000201FA R WM_POWERBROADCAST fSucceeded:True
<00006> 000201FA R WM_POWERBROADCAST fSucceeded:True
System now in standby mode
<00007> 000201FA S WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMRESUMESUSPEND dwData:00000000
<00008> 000201FA R WM_POWERBROADCAST fSucceeded:True
<00009> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00010> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00011> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
System now powered back up
Analysis
-
Going into standby sequence of messages is:
- PBT_APMQUERYSUSPEND (dwData: 00000001)
- Return True to indicate that a system suspend is OK.
- PBT_APMPOWERSTATUSCHANGE (dwData: 00000000)
- PBT_APMSUSPEND (dwData: 00000000)
-
Coming out of standby sequence of messages is:
- PBT_ APMRESUMESUSPEND (dwData: 00000000)
- PBT_ APMPOWERSTATUSCHANGE (dwData: 00000000)
- PBT_ APMPOWERSTATUSCHANGE (dwData: 00000000)
- PBT_ APMPOWERSTATUSCHANGE (dwData: 00000000)
Case 4: Battery from 100% to Critical State
This test was run by charging the system to 100% battery, starting Spy++ as outlined above and then discharging the battery over time. To accelerate the discharge rate a batch file repetitively copied files from a DVD to the hard drive and a hard drive search was done for all files containing a long random string. Items in italic are commentary added.
Test Sequence
Disconnect Power
<00001> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00002> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00003> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00004> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00005> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00006> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00007> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00008> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00009> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00010> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00011> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00012> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00013> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00014> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00015> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00016> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00017> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00018> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00019> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00020> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00021> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00022> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00023> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00024> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00025> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00026> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00027> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00028> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00029> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00030> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00031> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00032> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00033> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00034> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00035> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00036> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
<00037> 000201FA P WM_POWERBROADCAST (long)dwPowerEvent:PBT_APMPOWERSTATUSCHANGE dwData:00000000
The system issued an alert indicating that AC power should be connected
Note that the messages above were sent at even periodic intervals through the discharge cycle.
Analysis
The WM_POWERBROADCAST message by itself doesn’t provide enough details to know that AC power was disconnected or reconnected. When the message is received, GetSystemPowerStatus() must be called to get the details.
- In all cases WM_POWERBROADCAST is simply to inform that something has changed, but it doesn’t specify what has changed. GetSystemPowerStatus() must be called to know what the current power status is.
- If it is important for the application to know what the transition is from, a state variable must be maintained from the previous call to GetSystemPowerStatus(). The previous state and the current state would then be compared to determine what specifically has changed.
- Suspending a system comes in two parts, a request to suspend and then a notification that suspend is about to happen. Suspend can be stopped by any one application on the system.
Articles
- Windows* WM_POWERBROADCAST Code Sample
- Power Management:Designing Applications to Conserve Battery Life
- Mobile Computing Increases Demands on Hardware
Developer Centers
Community
Other Resources
For more complete information about compiler optimizations, see our Optimization Notice.


