Entries:
Comments:
Posts:

Loading User Information from Channel 9

Something went wrong getting user information from Channel 9

Latest Achievement:

Loading User Information from MSDN

Something went wrong getting user information from MSDN

Visual Studio Achievements

Latest Achievement:

Loading Visual Studio Achievements

Something went wrong getting the Visual Studio Achievements

You Can Take It With You, Part 1

  This article is about about mobility in the .NET Framework, specifically power awareness.
Arian Kulp's Blog

Difficulty: Easy
Time Required: 1-3 hours
Cost: Free
Software: Visual Basic or Visual C# Express Editions
Hardware:
Download:

In this column, the first of two, we're going to talk about mobility in the .NET Framework. What is mobility? Good question! Mobility means different things to different people. But key to mobility is that it allows you to respond to various changes in a mobile-enabled environment. For instance, if you are running on a laptop, you need to consider whether the system is on battery or plugged in. If it's on battery, how charged is the battery? If it's on AC, is the battery at full capacity or still charging? You also need to consider the network. As you move around with a laptop, your connection may come and go. Being aware of your network and power status are two important aspects of mobility. This column focuses on power awareness, while the next column will discuss network considerations.

Adding mobility support to an application makes it easier for you to play with available resources. If you know your network speed, you can tailor your data throughput accordingly. If you know that a network connection is unavailable, you might avoid even attempting a connection, and thus reduce the errors that users see. Finally, once you are aware of your power status, you can be more energy efficient when on battery power, especially when it gets down to a low level.

The application showcased in this article is available in both C# and Visual Basic. The links are at the top of the page. Use the code to jumpstart your own projects, or just to learn. To get started with this column, you'll need a copy of Microsoft Visual Basic Express Edition or Visual C# Express Edition, both free to download until November of this year. You can download either of these (and other Visual Studio Express editions) from http://msdn.microsoft.com/vstudio/express. This application shows off the most important features when running on a laptop or tablet computer but is fully usable on a desktop computer as well (it will simply report that no battery is present).

Working with Power

Up until .NET Framework 2.0, working with power information required calling into native Win32 libraries using the P/Invoke feature. This was okay if you had good code to copy and paste (or felt comfortable calling out to unmanaged code), but it never felt right. Writing all of your code using managed objects makes it both easier to write and easier to maintain.

.NET Framework 1.1 included support to determine one of several power states through an event. SystemEvents.PowerModeChanged event indicates one of three modes:

  • Resume — A system is resuming.

  • StatusChange — Power is changing between AC and battery, or other state.

  • Suspend — A system is suspending.

To my mind, the StatusChange mode is the strange one. To quote MSDN, "This might indicate a weak or charging battery, a transition from AC power from battery, or other change in the status of the system power supply." It just isn't very useful by itself. Knowing that you are switching between power sources ("or other change") doesn't make much of a difference if you are unable to read more information. This is where unmanaged code comes in. At this point, you would have been forced to call into the Win32 GetSystemPowerStatus function and then work with a structure containing the system power information. Not very elegant.

With 2.0, Microsoft added an additional property to the SystemInformation class: PowerStatus. This property returns an object of the same type, containing the same information. While it's true that the same unmanaged call is most likely being made behind the scenes, this property makes it possible for you to avoid importing the kernel32.dll and allows you to leverage your .NET skills. As an aside, let me add that SystemInformation class is a cornucopia of useful information that helps you to determine your number of monitors, resolution, keyboard/mouse preferences, computer name, and much, much more.

Obtaining battery information is now as easy as:

Visual Basic

Dim ps As PowerStatus = SystemInformation.PowerStatus

' .1 - 0 for current battery charge
Console.WriteLine("Level: {0}:", (ps.BatteryLifePercent * 100) & "%")

Visual C#

PowerStatus ps = SystemInformation.PowerStatus;

// .1 - 0 for current battery charge
Console.WriteLine("Level: {0}:", (ps.BatteryLifePercent * 100) + "%")

When the event fires, you can check to see if it was a power-related event, if the Mode property of the event is StatusChange, and then read the PowerStatus information. This is the approach taken in today's application. The following screen shot demonstrates the application when power is on AC and an Internet connection is available.

Figure 1. Running on AC

For the moment, let's ignore the Network region and focus on the Battery Info area. All five fields displayed are simply the properties of the PowerStatus object. The BatteryChargeStatus property can be any of the following:

  • Charging

  • Critical

  • High

  • Low

  • NoSystemBattery

  • Unknown

The NoSystemBattery value is set for—you guessed it—no battery on the system. This is why you can implement the power features in your application, and why it works fine on a desktop or laptop computer. The PowerLineStatus can be used to indicate if the system is on battery or AC. Its value can be one of the following:

  • Online (AC)

  • Offline (Battery)

  • Unknown (Hmm…)

The BatteryFullLifetime and BatteryLifeRemaining properties return the number of seconds representing the amount of time when the battery is full or at present level, respectively. The results can vary based on the specific battery and system. On my system, as you can see, my batteries don't report BatteryFullLifetime. This is indicated by a value of zero. For display in an application, create a TimeSpan object and format it like this:

Visual Basic

' How long is battery life based on current charge
Dim ts As New TimeSpan(0, 0, ps.BatteryLifeRemaining)

If ps.BatteryLifeRemaining > 0 Then
BatteryLifeRemainingTextBox.Text = ts.ToString()
Else
BatteryLifeRemainingTextBox.Text = "Unknown"
End If

Visual C#

TimeSpan ts = new TimeSpan(0, 0, ps.BatteryLifeRemaining);

if (ps.BatteryLifeRemaining > 0)
BatteryLifeRemainingTextBox.Text = ts.ToString();
else
BatteryLifeRemainingTextBox.Text = "Unknown";

Finally, the BatteryLifePercent property returns a number between 0 (fully discharged) and 1 (fully charged). Simply multiply by 100 to obtain a number to display. I've found that, at least on my system, it rarely wants to report 100%. But it is generally consistent with what I find in the system Power Properties control panel applet.

Figure 2. Running on battery

The complete method for determining power simply queries the properties of PowerStatus and formats the data. Note that this can be called at any time, not just based on the PowerModeChanged event. In this application, the method is called once during application initialization (in the form constructor), and then every time the event fires.

Visual Basic

Private Sub UpdatePowerInfo()
Dim ps As PowerStatus = SystemInformation.PowerStatus

' Charging, discharging, full, etc.
BatteryChargeStatusTextBox.Text = ps.BatteryChargeStatus.ToString()

' .1 - 0 for current battery charge
BatteryLifePercentTextBox.Text = (ps.BatteryLifePercent * 100) & "%"
PowerLineStatusTextBox.Text = ps.PowerLineStatus.ToString()

' How long is battery life based on current charge
Dim ts As New TimeSpan(0, 0, ps.BatteryLifeRemaining)

If ps.BatteryLifeRemaining > 0 Then
BatteryLifeRemainingTextBox.Text = ts.ToString()
Else
BatteryLifeRemainingTextBox.Text = "Unknown"
End If

' How long is battery life if fully charged (seconds)
ts = New TimeSpan(0, 0, ps.BatteryFullLifetime)

If ps.BatteryFullLifetime > 0 Then
BatteryFullLifetimeTextBox.Text = ts.ToString()
Else
BatteryFullLifetimeTextBox.Text = "Unknown"
End If

' PowerLineStatus is Online (AC), Offline (Battery), or Unknown
PowerModeToolStripStatusLabel.Text = _
IIf(ps.PowerLineStatus = PowerLineStatus.Online, "AC", "Battery")

End Sub

Visual C#

private void UpdatePowerInfo()
{
PowerStatus ps = SystemInformation.PowerStatus;
// Charging, discharging, full, etc.
BatteryChargeStatusTextBox.Text
= ps.BatteryChargeStatus.ToString();

// .1 - 0 for current battery charge
BatteryLifePercentTextBox.Text
= (ps.BatteryLifePercent * 100) + "%";
PowerLineStatusTextBox.Text = ps.PowerLineStatus.ToString();

// How long is battery life based on current charge
TimeSpan ts = new TimeSpan(0, 0, ps.BatteryLifeRemaining);

if (ps.BatteryLifeRemaining > 0)
BatteryLifeRemainingTextBox.Text = ts.ToString();
else
BatteryLifeRemainingTextBox.Text = "Unknown";

// How long is battery life if fully charged (seconds)
ts = new TimeSpan(0, 0, ps.BatteryFullLifetime);
if (ps.BatteryFullLifetime > 0)
BatteryFullLifetimeTextBox.Text = ts.ToString();
else
BatteryFullLifetimeTextBox.Text = "Unknown";

// PowerLineStatus is Online (AC), Offline (Battery), or Unknown
PowerModeToolStripStatusLabel.Text =
((ps.PowerLineStatus == PowerLineStatus.Online)
? "AC" : "Battery");

}

Next Steps

Integrating this with your application is easy. Best yet, your application will look more polished and complete when such information is reported in the status bar. You can even add settings to allow the user to modify actions based on battery level or AC/battery status. For instance, a game could automatically reduce its level of detail, or a dynamic screensaver its complexity, in order to reduce battery drain.

I've touched upon but not really discussed the Resume and Suspend modes of the PowerModeChanged event. Use these to flush unsaved data to disk before the system suspends, or to halt and resume file transfers.

Conclusion

Adding power awareness may sound like a complicated proposition, but the new support in .NET 2.0 makes it simple. Any application can take advantage of these features. Using available system information makes a good application even better, and can make it stand out from other choices.

Download the sample code at the top of the page, download a copy of Visual Basic or C# Express at http://msdn.microsoft.com/vstudio/express, and make your code better than ever. Adding power awareness will ensure that people can take your applications with them, wherever they go.

Follow the Discussion

  • Clint RutkasClint I'm a "developer"

    Clint Rutkas noticed a few people started to complain about Vista's battery performance directly due

  • Just code - Tamir KhasonJust code - Tamir Khason

    It's not a secret, that cool WDM (Aero user interface), announced in Windows Vista eat laptops' battery

  • MariaMaria

    Cool. How would this work on a cell phone running windows mobile? Do you think we will be able to get battery percentage? From what I've seen battery only comes in 5 ranges.

  • Dave Lloyd's 2 CentsDave Lloyd's 2 Cents

    The project I am working on right now is a software factory that will eventually allow it's users to

  • ARnARn

    How can you monitor power status change in a windows 5.0 smartphone using C#?

  • Monkey See, Monkey BuildMonkey See, Monkey Build

    Instead of complaining, fix the Vista Battery problem.

  • myMojomyMojo

    Interop'ng with Vista (Displaying Battery Power in the Taskbar)

  • JoseJose

    Hi... how can i do the same for a PDA?

  • Clint RutkasClint I'm a "developer"

    @Jose yes you can but I think the APIs for access are slightly different than they are with Win32 systems.

  • StrikerStriker

    Is there any way in windows to disable battery charging temporarily?

  • Clint RutkasClint I'm a "developer"

    @Striker, why would you want to?  You can just unplug the power supply then.  I also think the hardware, not software controls this.  I state this since your laptop will charge even if it is off.

  • Clint RutkasClint I'm a "developer"

    @Fullmetal my understanding there is a driver that lets windows communicate to the underlying hardware.  By abstracting out the exact details, windows then can call a method no matter what hardware it is on and it just gets data.  It is up the the hardware maker to provide that driver.  If the driver has a flaw in it ...

    Remember the vast amount of hardware Windows runs on.

  • FullmetalFullmetal

    @Coding4Fun I had a problem a while back where the machine reported battery not charging while plugged in. It was a driver related problem so I assume windows controls some aspect of the charging process while its running.

Remove this comment

Remove this thread

close

Comments Closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums,
or Contact Us and let us know.