Introduction
This article is about a silly little Windows Mobile application I wrote one dark and stormy night.
Background
So the weather in Minnesota has been pretty volatile this year with some thunderstorms like I haven't seen in a long time. One of the first ones to hit, and a number of them since, have knocked out my power in the middle of the night and since I like to keep the windows open as much as possible I've found myself stumbling around in the dark from room to room using my Pocket PC to provide some illumination.
Needless to say my shins have taken a beating.
"Why not put a real flashlight next to the bed" you ask? "Bah! I'll write a .NET Compact Framework application instead. It's way more fun!" is my answer.
Using the Code
Disabling the Screen Timeout
The all white full screen form is easy enough but the first real requirement of it is that the flashlight has to disable the backlight timeout while running (that first night I was a lot of screen tapping just to keep it as bright as possible).
This is done using the SetPowerRequirement
function on the coredll.dll (I like that they named the DLL CoreDll.dll just in case the DLL extension wasn't descriptive enough). SetPowerRequirement
allows an application to specify that it needs a certain power level from a particular device while running. The name of the backlight device is BKL1:
. Telling the OS that you need full power from the backlight will keep it from timing out.
The only trick to this method is that you need to be sure to call ReleasePowerRequirement
when you are done. I wrapped all this up in a PowerRequirement
class that implements IDisposable
so that it can be easily managed.
protected override void OnLoad(EventArgs e)
{
...
m_powerRequirement = new PowerRequirement("BKL1:", PowerState.FULL);
...
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (m_powerRequirement != null)
m_powerRequirement.Dispose();
}
base.Dispose(disposing);
}
The prototypes for the CE API to set and release power requirements look like:
[DllImport("coredll.dll")]
private static extern IntPtr SetPowerRequirement(string pvDevice,
PowerState DeviceState, int DeviceFlags, IntPtr pvSystemState, int StateFlags);
[DllImport("coredll.Dll")]
private static extern int ReleasePowerRequirement(IntPtr hPowerReq);
Controlling the Screen Brightness
Next I wanted a way to adjust the backlight brightness. This took some digging on the InterWebs but I eventually found enough hints to find something that works. That is to say it works on my HTC Touch running Windows Mobile 6. It sounds like backlight management can be very device and vendor specific, so this may or may not work on your device.
On the Touch the backlight brightness is managed by a registry setting HKCU\ControlPanel\Backlight\Brightness which is straightforward enough. Once you know that, it's just a matter of letting the OS know that you've changed the value. This is done using an event
(the Win32 flavor, not the .NET flavor). Oh and one caveat on the brightness adjustment: it doesn't work on the emulator; no matter what you set it to, it stays at full brightness.
public int Brightness
{
...
set
{
PowerStatus power = new PowerStatus();
if (power.PowerLineStatus == PowerLineStatus.Online)
SetBacklightValue("ACBrightness", value);
else
SetBacklightValue("Brightness", value);
RaiseBackLightChangeEvent();
}
}
private void SetBacklightValue(string name, int v)
{
RegistryKey key =
Registry.CurrentUser.OpenSubKey(@"ControlPanel\Backlight", true);
if (key != null)
{
key.SetValue(name, v);
key.Close();
}
}
private static void RaiseBackLightChangeEvent()
{
IntPtr hBackLightEvent =
CreateEvent(IntPtr.Zero, false, true, "BackLightChangeEvent")
if (hBackLightEvent != IntPtr.Zero)
{
SetEvent(hBackLightEvent);
CloseHandle(hBackLightEvent);
}
}
True Fullscreen
You would think that setting the Form
to maximized, getting rid of the control boxes, removing the border and making it a topmost window would provide a truly full screen window. This worked sometimes, but not every time. Often times the title bar and start menu would still show up over the flashlight window. To effectively get true fullscreen mode, one has to hit the CE API again.
protected override void OnLoad(EventArgs e)
{
...
SHFullScreen(this.Handle, SHFS_HIDETASKBAR |
SHFS_HIDESIPBUTTON | SHFS_HIDESTARTICON);
base.OnLoad(e);
}
private const int SHFS_SHOWTASKBAR = 0x0001;
private const int SHFS_HIDETASKBAR = 0x0002;
private const int SHFS_SHOWSIPBUTTON = 0x0004;
private const int SHFS_HIDESIPBUTTON = 0x0008;
private const int SHFS_SHOWSTARTICON = 0x0010;
private const int SHFS_HIDESTARTICON = 0x0020;
[DllImport("aygshell")]
static extern bool SHFullScreen(IntPtr hwnd, int dwState);
Points of Interest
The only real catch to this application that I haven't been able to figure out is battery life metrics. I wanted to be able to display estimated battery life remaining (you know for those "emergency, stuck in the elevator" situations where you might need to conserve on the battery). I got some code from OpenNETCF.org that uses the GetSystemPowerStatusEx
function but it never returns anything but null data on my Touch and on the Windows Mobile Device Emulator.
If anybody knows how to get meaningful data out of that method, please let me know. I have included the code and functionality in the application on the off chance it works on some other devices.
History
- 08-02-2008 - First posting
- 08-04-2008 - Added
SHFullScreen
call