First, you must understand that Windows Presentation Foundation itself does not inherently make power notifications available to a would-be power-aware application. You’ll see that for this functionality, my sample relies on the operating system—either Windows XP or Windows Vista (the operating systems on which Windows Presentation Foundation is designed to run).
Before I show you how to get this information into a Windows Presentation Foundation application, I should note that the power notification system on Windows Vista is more evolved than that on Windows XP. Windows Vista contains all the functionality of the Windows XP power notification system and then some, which can present quite a challenge. What are the notification systems, how do they differ, and how do you manage these differences to design a successful power-aware application? These are especially important questions in light of the fact that Windows Presentation Foundation applications are meant to run on both Windows XP and Windows Vista.
There are two excellent hands-on labs designed for those who are looking for sample code and hands-on experience with the Windows XP and Windows Vista power notification systems. These labs can be found at (for Windows XP) and (for Windows Vista). The labs cover the power notification systems as they would be used in managed code; however, they don’t represent how the power notification systems would be used specifically in Windows Presentation Foundation. Still, these labs provide an excellent starting point and cover the notification systems as a whole in greater detail than I can do here. I recommend you use them in conjunction with this article.
Another important point is that every application will have its own unique concerns in regard to power consumption. Not every application will perform 3D animation or write data to disk when the system is about to enter a suspended state. So, a single sample or hands-on lab cannot realistically address all the power needs of all applications. I would thus encourage developers to review the details of each notification system, as well as the measures taken in this article, within the context of his or her application’s needs.
In this article, I attempt to reconcile the differences between the Windows XP and Windows Vista power notification systems for use in a Windows Presentation Foundation application. The bulk of the work is performed inside a custom class: PowerAwareWindow. This class derives from the Window class (the element in which many applications live) and exposes much of the power-related system information and notifications in a fashion typical of the Windows Presentation Foundation—using custom dependency properties and events. The definition of this custom class can be found in the PowerAwareWindow.cs file (all of the code for this article is available for download from the MSDN® Magazine Web site).
The functions, variables, and associated structures that make power notifications from the operating system possible exist in native code. In order to make the work that is done in the PowerAwareWindow class more readable, these native elements are placed in a separate code file, NativeMethods.cs.
The sample application, which uses PowerAwareWindow, lives within the Window1.xaml and Window1.xaml.cs files. Rather than being hosted within a standard Window, the application is hosted within a PowerAwareWindow; it hooks up to the custom events and makes use of the custom dependency properties declared within the PowerAwareWindow to receive and respond to changes in the system’s power status.
Note that the sample code in the download differs slightly from the code presented here. Many of the native elements of the sample reside within the NativeMethods.cs file. Therefore, in the sample code, when native elements are referenced they are prefixed with NativeMethods. For example, the downloadable code refers to the operating system version as:
NativeMethods.VISTA_OS_VERSION
In this article, however, for clarity I simply refer to it as:
VISTA_OS_VERSION
In addition, the formatting differs slightly for better readability, the comments differ, and the code in the download includes some Debug.Assert calls. These calls are included as an extra precaution—some sections of the code assume that the application is running on Windows Vista and others assume it to be running on Windows XP.
The first step is to get notified of power-related system changes. As I mentioned earlier, this article does not provide a complete overview of the Windows XP and Windows Vista notification systems. I present a subset of this functionality specific to its use in the Windows Presentation Foundation. (For a complete overview of the notification systems, you should check out the Mobile PC Development Guides listed in the "Additional Resources" sidebar.)
I discuss two ways in which you can acquire notifications of system power changes: with the PowerModeChanged event on the SystemEvents class in the Microsoft.Win32 namespace in System.dll, and by trapping the WM_POWERBROADCAST window message.
The PowerModeChanged event is actually built on top of the WM_POWERBROADCAST message, but was done so before new power-related features were added to Windows Vista. As such, on Windows Vista the latter approach is more powerful. For example, when using only the PowerModeChanged event, an application would know nothing about the Windows Vista user’s defined power plan (to be discussed shortly).
The PowerModeChanged event passes a PowerModes enumeration to registered event handlers. This enum has three values: Resume, StatusChange, and Suspend. With this event, an application is notified when:
- The OS is about to resume from a suspended state (Resume)
- The power source has transitioned between AC and battery or some other change has occurred in the status of the system power supply (StatusChange)
- The operating system is about to be suspended (Suspend)
In the PowerAwareWindow, this event would normally be hooked up in the Window.Loaded event handler and unhooked in the Window.Closed event handler (see Figure 1). This, of course, is after the Window.Loaded and Window.Closed events are hooked up. This event covers much of the power-related information that an application might be interested in, and it may be the best option for your power-aware application. If an application is interested only in this information, then this method of receiving power events is much more straightforward than the window message trapping method that I’ll discuss momentarily.
The XP_SystemEvents_PowerModeChanged function is implemented in the code download and can be viewed there. It isn’t utilized in the sample as the code for hooking up the event is commented out and is included only for demonstration purposes.
The operating system sends out WM_POWERBROADCAST Window messages to alert listening applications of changes to power-related status or settings. However, in order to receive some of these notifications, an application must first register for them. The sample accompanying this article uses the window messages for power notifications (rather than the PowerModeChanged event) in the interest of thoroughness.
With WM_POWERBROADCAST, an application can receive the full gamut of system power change notifications. In order to receive window messages in a Windows Presentation Foundation application, an event handler must first be declared to receive window messages, like so:
void PowerAwareWindow_Loaded(object sender, RoutedEventArgs e)
{
WindowInteropHelper helper = new WindowInteropHelper(this);
HwndSource source = HwndSource.FromHwnd(helper.Handle);
source.AddHook(new HwndSourceHook(this.MessageProc));
...
}
This code declares the MessageProc function as the window message event handler. That function will check for the WM_POWERBROADCAST message (see Figure 2) and act accordingly.
The information about the event is contained in the wParam of the window message. The wParam can take many forms to indicate different power-related system events. For example, the following value indicates that either the power source changed or that the battery percentage remaining has changed:
const int PBT_APMPOWERSTATUSCHANGE = 0x000A;
These indicate that the system is about to enter or is in the process of leaving a suspended state:
const int PBT_APMSUSPEND = 0x0004; const int PBT_APMRESUMESUSPEND = 0x0007;
Some values are not available on all platforms. For example, the value shown below is available starting with Windows Vista and indicates that one of the following has changed: the power source, the power plan, the battery percentage remaining, or the monitor state.
const int PBT_POWERSETTINGCHANGE = 0x8013;
A complete list of such events can be found in the Power Management documentation. For comparison, the PBT_APMPOWERSTATUSCHANGE, PBT_APMSUSPEND, and PBT_APMRESUMESUSPEND wParams are analogous to the StatusChange, Suspend, and Resume PowerModes in the PowerModeChange event, respectively.
It is important to note the difference between wParam values for PBT_APMPOWERSTATUSCHANGE and the PBT_ POWERSETTINGCHANGE. The latter can be understood as a Windows Vista-only superset of PBT_APMPOWERSTATUSCHANGE. It indicates all the power-related changes that PBT_APMPOWERSTATUSCHANGE indicates as well as other information specific only to Windows Vista, such as power plans and monitor state. Both of these wParams exist and are passed along with the WM_POWERBROADCAST window message on Windows Vista, but processing both would result in redundancy in this sample when running on Windows Vista.
The PBT_POWERSETTINGCHANGE wParam, however, will not be sent to a Windows Vista application until the application registers for power setting notifications (PBT_APMPOWERSTATUSCHANGE is received without registration). This is a very important step for receiving power notifications specific to Windows Vista.
To register for power setting notifications on Windows Vista, the first step is to make the RegisterPowerSettingNotification function available for use in the application. You can do that with the following P/Invoke function definition:
[DllImport(@”User32.dll”, SetLastError=true,
CallingConvention=CallingConvention.StdCall)]
static extern IntPtr RegisterPowerSettingNotification(
IntPtr hRecipient, ref Guid PowerSettingGuid, Int32 Flags);
This function returns a handle that will be used to unregister for the events when the application is shutting down.
The Flags passed into this function indicate to the operating system how the application would like to receive notifications. For this sample, I declare this as:
const int DEVICE_NOTIFY_WINDOW_HANDLE = 0x00000000;
This indicates to the registration function that notifications are to be sent to the application using the WM_POWERBROADCAST window message with a wParam of PBT_POWERSETTINGCHANGE. The other option for Flags is relevant for OS services and is explained in the RegisterPowerSettingNotification documentation mentioned earlier.
The PowerSettingGuid value passed to the registration function indicates to the operating system the notifications in which the application is interested. Figure 3 shows the four PowerSettingGuid values you’re probably most interested in.
Other notification GUIDs are available and can be used to get notified for events such as when the system is entering or exiting an away mode or when the system will be moving into an idle state in the near future and the current time is a good time to perform background or idle tasks.
In the sample, I have grouped all the Windows Vista power registration into one function (see Figure 4). Similarly, I have also grouped all the unregistration into one function. Registration occurs when the PowerAwareWindow loads (the Window.Loaded event is handled by PowerAwareWindow_Loaded function) and unregistration occurs when it closes (Window.Closed handled by PowerAwareWindow_Closed).
Registration introduces one of the main issues that I address in this sample—to create a consistent approach to power-awareness in one Windows Presentation Foundation application that accounts for the differences regarding power notifications on Windows XP and Windows Vista. The RegisterPowerSettingNotification and UnregisterPowerSettingNotification functions exported from User32.dll are not available on operating systems prior to Windows Vista; as a result, any code that tries to use these functions should only do so after first ensuring the functions are available.
It is important for your application to detect the operating system and act accordingly. To this end, my sample has a private variable marked readonly for storing this information:
readonly int _osVersion = Environment.OSVersion.Version.Major;
The operating system major versions for Windows Vista and Windows XP are:
const int VISTA_OS_VERSION = 6; const int XP_OS_VERSION = 5;
At this point, the PowerAwareWindow_Loaded and PowerAwareWindow_Closed functions should look something like that shown in Figure 5. At this point, the application is receiving power notifications via window messages in the MessageProc function. Once the power notifications are received, the application needs to respond appropriately.
In many cases it is necessary for a power-aware application to declare and make use of custom dependency properties other than the ones declared in this sample. Note that custom dependency properties is an advanced topic. If you need more background before reading this section, check out the Custom Dependency Properties documentation.
While these custom dependency properties may seem complicated, they provide a lot of power and flexibility for an application that uses the PowerAwareWindow. The custom dependency properties declared in the sample are PowerPlan, MonitorOn, RemainingBattery, and RunningOnBattery.
PowerPlan exposes the current user-specified power plan. This piece of information is specific to Windows Vista. On Windows XP this will always be a default value (Automatic). The associated PowerPlanChanged event does not fire on Windows XP as there is no notion of power plans on that OS.
The PowerPlan enumeration is defined as:
public enum PowerPlan
{
Automatic,
HighPerformance,
PowerSaver,
};
In the Windows Vista UI, these are called "Balanced," "High Performance," and "Power Saver," respectively. The dependency property registration looks like the code shown in Figure 6.
MonitorOn exposes the current state of the monitor (display)—either on or off. This piece of information is specific to Windows Vista. On Windows XP, it will always have a default value (True). The associated MonitorOnChanged event does not fire on Windows XP as there is no notion of Monitor state in that OS.
The dependency property registration looks very similar to the one described for PowerPlan, except that the property is of type Boolean, the property is named MonitorOn, and the corresponding event is MonitorOnChanged. The full implementation for this and the rest of the dependency properties can be found in the code download.
RemainingBattery exposes the percentage of the battery currently remaining—ranging from 0 to 100 percent. For this case, the dependency property registration is very similar to that of the previous two dependency properties.
RunningOnBattery is true if the system is running on a battery and false if it is running on AC power.
As with the custom dependency properties, it is also often necessary for a power-aware application to declare and make use of custom events. (If you need more background on custom events, check out the Routed Event Overview). The custom events in my sample are PreviewSystemResuming, SystemResuming, PreviewSystemSuspending, and SystemSuspending.
PreviewSystemResuming occurs when the system is resuming from a suspended state. The Preview part of the event indicates that the event’s routing strategy is Tunnel as opposed to Direct or Bubble. The event registration looks like the code shown in Figure 7.
SystemResuming occurs when the system is resuming from a suspended state. This uses the Bubble routing strategy version of the PreviewSystemResuming event. The event registration looks like the code shown in Figure 8.
PreviewSystemSuspending occurs when the system is about to enter a suspended state. The Preview part of the event indicates that the event’s routing strategy is Tunnel, as it is with PreviewSystemResuming.
SystemSuspending occurs when the system is about to enter a suspended state. As with SystemResuming, it uses the Bubble routing strategy.
The custom dependency properties aren’t much use unless they contain the latest system information. Similarly, the custom power events need to be raised appropriately. Let’s look at this now, as well as some of the trickier things involved in getting Windows Presentation Foundation power-awareness to function well for a single application that runs on both Windows XP and Windows Vista.
Let’s start with a look at important Windows XP power structures. First there’s the SYSTEM_POWER_STATUS (see Figure 9). As you can see, this sample uses the ACLineStatus and BatteryFlag enumerations.
The SYSTEM_POWER_STATUS is returned from the GetSystemPowerStatus function. It is made available to the application with the following import:
[DllImport(“Kernel32.DLL”, CharSet=CharSet.Auto, SetLastError=true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool GetSystemPowerStatus(
[In, Out] SYSTEM_POWER_STATUS SystemPowerStatus);
This function is called whenever the WM_POWERBROADCAST message is received with the PBT_APMPOWERSTATUSCHANGE wParam. This wParam indicates that something in the system power has changed and the GetSystemPowerStatus function gives the application access to that information. That information is returned inside the SYSTEM_POWER_STATUS that is passed in.
As discussed in the Detecting the Operating System section, the dependency properties need to be initialized when the application is loading in order for them to be up-to-date (see Figure 5). This is not necessary in Windows Vista, as the operating system makes the application aware of the current system power status through the window message when the application registers for power notifications. This, however, does not happen on Windows XP and therefore initialization is necessary. This initialization is done in the PowerAwareWindow_Loaded function when the operating system is detected and appears as follows:
void InitializeDependencyPropertiesForXP()
{
if (GetSystemPowerStatus(this._xpPowerStatus))
{
this.RunningOnBattery =
(ACLineStatus.Battery == _xpPowerStatus.ACLineStatus);
this.RemainingBattery = _xpPowerStatus.BatteryLifePercent;
}
this.MonitorOn = true;
this.PowerPlan = PowerPlan.Automatic;
}
At this point it is important to point out that there isn’t a Windows XP monitor or power plan notification analogous to the Windows Vista notification. Therefore, when a Windows XP application attempts to get these values, default values will be returned. And even if the application hooks up the MonitorOnChanged event or the PowerPlanChanged event, after initialization nothing will trigger the firing of the events.
Next up are the Windows Vista power structures. POWERBROADCAST_SETTING is the main Windows Vista power struct:
struct POWERBROADCAST_SETTING
{
public Guid PowerSetting;
public UInt32 DataLength;
}
In the official definition of the struct, there is a third member present: Data. As indicated in the struct, this can vary in size, being either a GUID or a DWORD. Thus, declared within the application is a custom variation of this struct that can hold either of these data types (note that this struct doesn’t mimic the layout of the original native structure and thus can’t be used for marshaling; it’s simply used so that the values can continue to be passed around within the application in a strongly typed fashion):
struct my_POWERBROADCAST_SETTING
{
public IntPtr wParam;
public Guid PowerSetting;
public int PowerChangeData;
public Guid PowerPlanGuid;
}
This struct also includes the wParam so that with this custom variation, all relevant data can be passed from the window message handler to the application’s Windows Vista message handler (defined later) in one struct.
So when receiving the WM_POWERBROADCAST window message on Windows Vista along with a wParam of PBT_POWERSETTINGCHANGE, the lParam associated with the message is a pointer to a POWERBROADCAST_SETTING struct that contains information about the change in the system’s power status.
One last important bit of information concerns how Windows Vista defines Power Plans. Maximum Power Savings involves very aggressive power-savings measures to help stretch battery life:
static Guid GUID_MAX_POWER_SAVINGS =
new Guid(“a1841308-3541-4fab-bc81-f71556f20b4a”);
No Power Savings uses almost no power savings measures:
static Guid GUID_MIN_POWER_SAVINGS =
new Guid(“8c5e7fda-e8bf-4a96-9a85-a6e23a8c635c”);
Finally, the typical Power Savings power plan uses relatively aggressive power savings measures:
static Guid GUID_TYPICAL_POWER_SAVINGS =
new Guid(“381b4222-f694-41f0-9685-ff5bb260df2e”);
These correspond to PowerPlan.PowerSaver, PowerPlan.HighPerformance, and PowerPlan.Automatic, respectively. As mentioned earlier, they appear as Power Saver, High Performance, and Balanced in the Windows Vista UI, respectively.
The code in Figure 10 provides a high-level look at the MessageProc function. There are two important points to explain here. The first point is how the work is sent to each of the handlers. Second is how (and when) data is grabbed in the event of a WM_POWERBROADCAST message on Windows Vista.
Normally, sending the work to each of the handlers would be as simple as calling functions defined in the sample code. These functions would handle the message appropriately when the application is running on either Windows XP or Windows Vista. In this case, though, a bit more precaution has been taken to prevent system hangs. If, for example, the function that handles the message is complicated and processor-intensive, then control wouldn’t be returned to the window message handle immediately and this could result in noticeable system hangs. To avoid hangs like this, the work is sent to the Windows Vista and Windows XP handlers via a post to the Dispatcher thread (see Figure 11).
The message will be handled asynchronously at the specified priority on the thread with which the Dispatcher is associated; control is returned immediately to the MessageProc function after the work is posted to the Dispatcher. More on the Dispatcher and Windows Presentation Foundation threading can be found in the WPF Fundamentals Threading Model documentation.
Now for the topic of grabbing data for Windows Vista power events. The wParam portion of the WM_POWERBROADCAST window message is crucial to understanding the nature of the message, as explained previously. On Windows XP, this is all that is necessary for successfully handling the power message. On Windows Vista, however, this wParam can indicate that the lParam in the message is a pointer to data necessary for determining the nature of the message. Figure 12 shows how I copy that data out of the lParam pointer. There you can see the MessageProc function with these changes.
Once you have the relevant data for the message, you need to update the relevant properties and fire the relevant events. Considering all the work that’s been done thus far to get notifications and set up custom dependency properties, this step is actually very straightforward. All it involves is either assigning the data provided by the operating system to the appropriate application variables or raising the appropriate custom events.
Now let’s take a look at an application that is hosted within a PowerAwareWindow. At this level, power-awareness fits very well into the Windows Presentation Foundation model and creating a power-aware application that runs on both Windows XP and Windows Vista is quite straightforward.
The first thing to examine is the user interface, as defined in Window1.xaml. Note that the application lives within a Power- AwareWindow:
<local:PowerAwareWindow x:Class=”WPFPower_Aware.Window1”
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
xmlns:local=”clr-namespace:WPFPower_Aware”
x:Name=”MainWindow”
Title=”WPF Power Aware Application” Height=”480” Width=”550”
Loaded=”Window1_Loaded”
>
...
</local:PowerAwareWindow>
As a result, the XAML file can make use of the custom dependency properties for data binding. My sample, for example, contains a status bar at the bottom of the window. Within the status bar, there are two pieces of power-related data—a text block indicating the current system power source and a progress bar indicating the current percentage of remaining battery power. The values assigned to these are data-bound to their corresponding dependency properties.
You’ll find that data binding is quite simple. Consider the progress bar, for example:
<ProgressBar IsIndeterminate=”False” x:Name=”myBatteryProgressBar”
Width=”200” Height=”20”
Value=”{Binding ElementName=MainWindow,
Path=RemainingBattery, Mode=OneWay}” />
With this little bit of markup, the progress bar will always be up-to-date and no codebehind intervention is necessary. You can even data-bind to your own custom control, such as a battery meter, to display this information!
The power-source text block is somewhat more complicated as it involves converting from a Boolean value (RunningOnBattery) to a string for the text block. If you’d like to view the details of this, take a look in the sample code.
TIf you run the sample application, you’ll see two animation elements. The one on the left is controlled in the codebehind, the other is controlled in XAML. The animation that is controlled by XAML starts and stops when the RunningOnBattery property is false and true, respectively.
The snippet in Figure 13 is for an animation that demonstrates the power of custom dependency properties via their use in XAML. With this piece of XAML, no code intervention is necessary to stop and start the animation. And this is just the beginning—there’s much more you can do with animations and triggers in XAML. For more information, see the Windows Presentation Foundation Animation Overview and the Trigger Class documentation.
As I mentioned, the left element in the sample app has an animation that is controlled in the codebehind. When a relevant system power event occurs, the current power state of the system is used to determine if the animation should be paused to conserve power. First, the animation gets set up and then the custom events are hooked up. The necessary code for this is found in Window1 .xaml.cs (see Figure 14).
Deciding how and when the application should take measures to conserve power depends largely on the behavior and needs of your application. In this sample, the decision is made as follows, and the power event handlers make use of this function in the appropriate event handlers:
bool ShouldStopAnimation()
{
// If the monitor is off, or if we’re running on a battery
// and the user hasn’t explicited requested high performance,
// stop the animation
return
!MainWindow.MonitorOn ||
(MainWindow.PowerPlan != PowerPlan.HighPerformance &&
MainWindow.RunningOnBattery);
}
One thing to note in this sample is that power events are reported in a list box in the UI. Here, for example, is the RunningOnBatteryChanged event handler:
void Window1_RunningOnBatteryChanged(
object sender, DependencyPropertyChangedEventArgs e)
{
myEventsListBox.Items.Add(
“RunningOnBattery changed - now it’s {0}”, (bool)e.NewValue);
if (ShouldStopAnimation()) myStoryboard.Pause(this);
else myStoryboard.Resume(this);
}
You can learn more about other measures an application can take to conserve power by taking a look in the Mobile PC Power and Device Awareness documentation.
This article and the accompanying code provide a starting point from which you can learn to make your Windows Presentation Foundation applications power-aware. Note that there is a lot more to power awareness and the Windows Presentation Foundation than I’ve discussed here. Therefore, I highly recommend that you review the resources mentioned throughout this article before you design your power-aware application. You’ll discover many more capabilities and techniques that will help you tailor the best solution for your program.
For general information regarding power and device management, and ideas on how you can reduce power consumption, check out these MSDN links for helpful documentation:
- Mobile PC User Experience Guidelines for Developers: Power and Device Awareness
- Mobile PC Development Guide: Power Management on Windows Vista
- Mobile PC Development Guide: Power Management on Windows XP
- Win32 and COM Development: Power Management
For an overview of the Windows Presentation Foundation features used in this article, check out these links:
- Routed Event Overview
- Custom Dependency Properties documentation
- WPF Fundamentals: Threading Model documentation
- Windows Presentation Foundation Data Binding Overview
- Windows Presentation Foundation: Animation Overview
And for specific definitions of certain functions, classes, and enumerations used in this article, see these links:
- SystemEvents.PowerModeChanged Event documentation
- WM_POWERBROADCAST documentation
- RegisterPowerSettingNotification documentation
- SYSTEM_POWER_STATUS documentation
- POWERBROADCAST_SETTING documentation
- Trigger Class documentation