今年明尼苏达州的天气变化无常,经历了一些久违的雷暴。其中第一次雷暴,以及随后的几次,都在深夜让家中断电。喜欢尽可能地开着窗户,因此在黑暗中,不得不依靠Pocket PC手机来提供照明,以便在房间之间摸索。
不用说,小腿因此受了不少苦。可能会问:“为什么不在床边放一个真正的手电筒呢?”回答是:“为什么不写一个.NET Compact Framework应用程序呢?这样更有趣!”
实现一个全屏的白色界面并不难,但手电筒的第一个要求是必须在运行时禁用背光超时(第一晚不得不频繁地点击屏幕,以保持尽可能的亮度)。
这是通过调用coredll.dll中的SetPowerRequirement函数来实现的(喜欢他们将DLL命名为CoreDll.dll,以防DLL扩展名不够直观)。SetPowerRequirement允许应用程序在运行时指定它需要来自特定设备的一定电力水平。背光设备的名称是BKL1。告诉操作系统需要背光的全功率,可以防止它超时。
使用这种方法的唯一技巧是,当完成后一定要调用ReleasePowerRequirement。将所有这些都封装在一个实现了IDisposable的PowerRequirement类中,以便可以轻松管理。
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);
}
设置和释放电力需求的CE API原型如下:
[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);
接下来,想出了一种调整背光亮度的方法。这需要在互联网上进行一些挖掘,但最终找到了一些线索,找到了一个可行的方法。也就是说,它在HTC Touch上运行Windows Mobile 6时有效。听起来背光管理可能非常依赖于设备和供应商,所以这可能不适用于设备。
在Touch上,背光亮度由注册表设置HKCU\ControlPanel\Backlight\Brightness管理,这足够简单。一旦知道了这一点,就只需要让操作系统知道已经改变了这个值。这是通过一个事件(Win32风格的,不是.NET风格的)来完成的。哦,还有关于亮度调整的一个警告:它在模拟器上不起作用;不管设置什么,它始终保持全亮度。
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);
}
}
可能认为将Form设置为最大化,去掉控制框,移除边框,并将其设置为最顶层窗口,就可以提供一个真正的全屏窗口。这有时有效,但并不总是有效。很多时候,标题栏和开始菜单仍然会显示在手电筒窗口之上。为了有效地获得真正的全屏模式,必须再次调用CE API。
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.dll")]
static extern bool SHFullScreen(IntPtr hwnd, int dwState);
这个应用程序唯一真正的问题是还没有弄清楚电池寿命指标。想能够显示剩余的估计电池寿命(知道的,对于那些“紧急情况,被困在电梯里”的情况,可能需要节省电池)。从OpenNETCF.org得到了一些代码,它使用GetSystemPowerStatusEx函数,但它在Touch和Windows Mobile设备模拟器上从未返回过任何数据。
如果有人知道如何从该方法中获取有意义的数据,请告诉。已经将代码和功能包含在应用程序中,以防它在其他设备上有效。