Anyway I thought I would mention a few things that I have found out over the
last week or 2. I have been trying to create an app that displays
percentage battery in the System Tray. "Already done" you say.. I don't
like way XP does it. I have to hover my pointer (mouse) over the icon to
get a percentage. The icon itself only has a couple of images: full, half,
empty. My battery was at 68% and the icon was still "full". That doesn't
help me at all.
So I started to roll my own. Only to find that there are a couple of
issues:
1. I would have to dynamically create the ico if I didn't want to create 100
different images (one for each percent).
2. The power info is in the Win API, involving PInvoke.
3. I only want a NotifyIcon, not a Windows Form as well.
Thankfully I found a solution for each of these hurdles:
1. The blood sweat and tears of bmp to ico conversion has been done already
by Joshua Flanagan
http://flimflan.com/blog
2. I managed to find the Win API info for Power Management:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/power/base/
getsystempowerstatus.asp
3. There is a great example of how to create a WinForm app that doesn't
display the Form by Jessica Fosler
http://windowsforms.net/articles/notifyiconapplications.aspx
Putting it all together:
I have a WinForm App with a custom PowerMeterApplicationContext. In my
appContext I have a NotifyIcon and a Timer. When the timer elapses the
battery life percent is read via the Win API and converted to an icon.
NotifyIcon.Icon is updated. We all lived happily ever after.
private void iconTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
SystemPowerStatus stat = new SystemPowerStatus();
string str_BatteryLifePercent;
try
{
PowerMeter.GetSystemPowerStatus(stat);
}
catch
{
str_BatteryLifePercent = "ER";
}
int int_BatteryLifePercent = stat.BatteryLifePercent;
if (int_BatteryLifePercent == 100)
str_BatteryLifePercent = ":)";
else if (int_BatteryLifePercent > 100)
str_BatteryLifePercent = ":(";
else
str_BatteryLifePercent = int_BatteryLifePercent.ToString();
// Drawing the ico with the help of FlimFlan
Bitmap bmp = new Bitmap(16, 16, PixelFormat.Format24bppRgb);
using (Graphics g = Graphics.FromImage(bmp))
{
g.FillEllipse(Brushes.Red, 0, 0, 16, 16);
g.DrawString(str_BatteryLifePercent, iconFont, Brushes.White, 0, 1);
}
powermeterNotifyIcon.Icon =
FlimFlan.IconEncoder.Converter.BitmapToIcon(bmp);
}
And the PInvoke stuff.. Firstly the actuall DllImport to the
GetSystemPowerStatus function:
[DllImport("Kernel32.dll", CharSet=CharSet.Auto)]
public static extern bool GetSystemPowerStatus(
[In, MarshalAs(UnmanagedType.LPStruct)]
WinAppPowerMeter.SystemPowerStatus status
);
And finally the struct:
[StructLayout(LayoutKind.Sequential)]
public class SystemPowerStatus
{
public byte ACLineStatus;
public byte BatteryFlag;
public byte BatteryLifePercent;
public byte Reserved1;
public int BatteryFullLifeTime;
public int BatteryLifeTime;
}
And that's all it took.
Have fun,
Scotty.