Windows移动电源管理(译文)
By S.F.
本文链接 https://www.kyfws.com/news/windows-mobile-power-management/
版权声明 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
- 18 分钟阅读 - 8857 个词 阅读量 0Windows移动电源管理(译文)
原文地址:https://www.codeproject.com/Articles/28886/Windows-Mobile-Power-Management
原文作者:Joel Ivory Johnson
译文由本站翻译
前言
收集有关与电源管理器进行交互以利用或禁用Windows Mobile设备中的节能功能的信息.
介绍
作为MSDN支持论坛和其他在线开发社区的定期读者,我看到有关Windows Mobile设备上电源管理和控制方面的几个问题(经常发生).有时,开发人员希望减少对电源的需求,而在其他时候,禁用省电功能.然后,有一些编码模式有助于更快地耗尽电池电量.为了回应社区的声音,我收集了有关Windows Mobile电源管理的信息.虽然本文档中提到了Windows Mobile Standard设备,但它以Windows Mobile Professional为中心.电源管理是一个很大的领域,我需要讨论很多内容并添加到本文中.但是,在这一点上,我认为所提供的信息可能对许多人有所帮助,因此,我决定提供该文章,并提供在一段时间内不断发展的计划,直到达到我认为的程度为止.它完成了.如果文章太大,则可能会分解为多个文章.
关于守则
本文附带的代码示例是一些小程序的集合,这些小程序演示了一个或两个电源管理概念.这些程序依赖于几个本地调用.没有在每个程序中声明P/Invokes,而是有一个包含所有必要的本机调用的项目,示例程序通过该项目中的类进行其低级调用.我通常将这些调用包装在一个帮助器中,但避免在这些示例中使用一个,以免在希望演示的调用之间增加一层分隔.所有示例代码都在C#中,带有P/Invoke调用.由于列出了所用的API,因此这些信息也应对C ++开发人员有用. 所附代码中的示例程序说明了以下内容:
驱动程序依赖性
如前所述,电源管理的某些方面处理低级呼叫.因此,由于依赖于驱动程序实现,因此某些代码示例可能无法在您的设备上运行.在收集此信息的过程中,我在自己拥有的Windows Mobile 6设备(现在为6.1设备)上执行了固件更新.一些示例停止了工作,问题的原因是该特定设备的制造商决定在固件更新中不使用标准电源管理器.许多代码示例将在Windows Mobile 5设备上运行,但是我的目标是Windows Mobile6.在Windows Mobile 5上运行某些示例可能会引发"不支持"的异常.在下周内,我计划解决所有Windows Mobile 5兼容性问题.
术语:Windows Mobile Professional和Windows Mobile Standard
本文中信息的某些部分特定于Windows Mobile Professional和Windows Mobile Standard.我不是使用这些术语来引用这些设备类,而是将这些平台恢复为较旧的名称.对于没有触摸屏的设备,我将使用术语智能手机代替Windows Mobile Standard设备.对于带触摸屏的设备,我将使用术语Pocket PC代替Windows Mobile Professional设备.尽管这些术语被认为已过时,但我发现从视觉上区分这两个词更容易.当谈到两个平台共有的属性时,我将使用术语" Windows Mobile".
“关闭"是什么意思?
讨论的基础是对” off"一词的理解.典型的电灯开关上的典型的灯泡是打开还是关闭,两者之间没有任何状态.从历史上讲,许多电气设备都可以这样说,但是在当今世界,除非中断电源,否则许多设备不会经常使用真断电状态.断开状态已变为暂停状态或低功耗状态.智能手机和Pocket PC设备上的电源行为是不同的,因此我将分别对其进行描述.但是,在这两个平台之间的共同点是,如果我曾经说过设备处于"关闭"状态,则表示没有电源流过设备,而当典型用户说"关闭"时,则表示设备屏幕处于关闭状态无论设备实际上是在消耗功率还是在执行操作.
智能手机(r)
Windows Mobile Standard设备通常处于打开状态.如果您将手机切换至真正的关机状态,则将无法接听电话.如果您不与设备进行交互,则屏幕将关闭电源,处理器将以较低的速度运行,但仍可以运行.根据Windows Mobile Team博客的说法,使设备始终处于开机状态有助于更好地节能.这种模式的一个潜在问题是程序编写不当会导致处理器消耗的功率超过其空闲时所需的功率.
掌上电脑
Windows Mobile Professional具有我们应该了解的四种电源模式.在完全供电状态下,设备的屏幕和背光均会亮起.如果您按下电源按钮或不与设备互动,那么经过这么长时间,它要么进入"无人值守"状态,要么进入暂停状态.如果程序指定需要继续运行,则设备将进入无人参与状态.在无人值守状态下,设备仍在运行,但屏幕和背光均已关闭.用户会将其视为关闭状态,但设备仍处于唤醒状态.如果没有程序需要继续运行,则设备将进入暂停状态.在挂起状态下,所有正在运行的程序仍在内存中,但是由于CPU处于暂停状态,它们没有任何进展.我们关注的最终状态是真正的关闭状态.
权力国
系统电源状态
Windows Mobile设备具有几种预定义的电源状态.这些状态中的某些特定于Pocket PC,某些特定于Smartphone,而另一些则可以在两者上找到.下表列出了电源状态,并描述了将设备转换为所述电源状态时发生的情况. P表示状态适用于Pocket PC,S表示状态适用于智能手机. 请注意,程序可以更改设备在电源状态之间的转换.这样的程序的一个例子是即时通讯程序,它可以防止设备挂起,以便它可以继续接收消息.
设备驱动器电源状态
Windows Mobile设备的各个组件可以具有自己的电源状态,其中最引人注目的是屏幕和背光.背光或屏幕关闭时,设备可以打开(使用媒体播放器时的常用电源配置).设备驱动程序的电源状态更抽象一些. 根据硬件和驱动程序,其中某些电源状态是相同的.当需要更改设备的电源状态时,应通过" DevicePowerNotify"传递更改状态的请求.请求更改电源状态并不能保证会更改状态.驱动程序仍然可以自行决定是否更改电源状态(请记住,您的程序不是唯一正在运行的程序,也不是唯一会影响电源状态的程序).
请求和更改电源状态
如果需要监视或查询电源状态,请使用本机函数[GetDevicePower](http://msdn.microsoft.com/zh-cn/library/aa930541.aspx)
.您的程序可以通过RequestPowerNotifications请求电源更改事件的通知,而不是通过[GetDevicePower](http://msdn.microsoft.com/zh-cn/library/aa930541.aspx)轮询状态/msdn.microsoft.com/zh-CN/library/aa932427.aspx). 如果您的应用程序需要Windows Mobile设备保持在某种电源状态,则使用[SetPowerRequirement](http://msdn.microsoft.com/zh-cn/library/ms920689.aspx)来请求您的电源状态为应用需求.操作系统将确保设备的电源状态不低于要求的水平.当不再需要电源状态时,请调用
ReleasePowerRequirement`.若要设置设备驱动程序的电源状态而不是表达最低要求,请使用SetDevicePower.
可以通过本机函数SetSystemPowerState设置系统的电源状态.可以使用SetDevicePower设置Windows Mobile设备中各个硬件项目的电源状态.
(您也可以要求在某些电源更改事件期间自动启动程序.有关更多详细信息,请参见在Windows Mobile上自动启动应用程序.)
当您有需要在无人参与模式下运行的应用程序时,请使用本机函数PowerPolicyNotify()通知操作系统您需要设备继续运行而不暂停.这是一个引用计数API.对于每次使用" TRUE"调用此功能,还必须使用" FALSE"调用此功能,以确保设备不会不必要地保持较高功率.
没有电源管理器
Windows Mobile设备使用电源管理器时,Windows CE设备可能会也可能不会.对于不支持电源管理器API的设备,可以使用对GWES系统的调用以编程方式关闭系统电源.如果电源管理器API不可用,则仅使用GWES功能. GwesPowerOffSystem挂起系统.另外,我们也可以通过使用keybd_event函数生成键盘消息来模拟按下电源按钮,如下所示:
keybd_event( VK_OFF,0, KEYEVENTF_SILENT,0);
keybd_event( VK_OFF,0, KEYEVENTF_SILENT|KEYEVENTF_KEYUP,0);
无论哪种情况,由于消息必须由GWES处理,因此函数调用将返回,并且在系统挂起之前将执行几行代码.如果您需要系统在调用此方法后停止工作,请致电Sleep.
枚举硬件
通过首先在HKLM \ Drivers \ Active中的注册表中查找,可以找到Windows CE设备中的活动硬件.在该位置可以找到一组带有数字名称的注册表项.查看这些键中的每个键内的" Name"字符串将给出硬件的名称.在示例程序CePowerState中,我使用以下代码枚举硬件:
// Get the names of all of the subkeys that
// refer to hardware on the device.
RegistryKey driverKeyRoot =
Microsoft.Win32.Registry.LocalMachine.OpenSubKey("Drivers\\Active");
string[] keyName = driverKeyRoot.GetSubKeyNames();
//We are saving this information to list for sorting later
List<string> deviceNameList = new List<string>();
for (int i = 0; i < keyName.Length; ++i)
{
//Get the name of the hardware and add it to the list
RegistryKey currentKey = driverKeyRoot.OpenSubKey(keyName[i]);
string deviceName = currentKey.GetValue("Name") as string;
if(deviceName!=null)
deviceNameList.Add(deviceName);
}
//Sort the list
deviceNameList.Sort();
//Add the list to the list box so the user can select hardware
for (int i = 0; i < deviceNameList.Count; ++i)
{
lstDeviceList.Items.Add(deviceNameList[i]);
}
示例程序CePowerState将枚举在此位置找到的所有硬件,并允许您通过调用SetDevicePower直接设置硬件的电源状态.屏幕背光通常(但不总是)被命名为" BKL1:",而声音设备通常被命名为" WAV1:".将背光灯的电源状态设置为" D0"将其打开,将" D4"将其关闭.如果您正在播放音频并将WAV1:的电源状态设置为D4,则直到电源状态重新设置为D0为止,将不再听到声音.这是设置设备电源状态的代码.
//Get the name of the selected hardware
string deviceName = lstDeviceList.SelectedItem as string;
//Get the power state to which the device will be changed
CEDEVICE_POWER_STATE state = (CEDEVICE_POWER_STATE)Enum.Parse(
typeof(CEDEVICE_POWER_STATE), lstPowerState.SelectedItem as string,true);
//deviceHandle = CoreDLL.SetPowerRequirement(deviceName, state,
(DevicePowerFlags)1 , IntPtr.Zero, 0);
CoreDLL.SetDevicePower(deviceName, DevicePowerFlags.POWER_NAME, state);
电源状态的已注册设备电源设置
有某些电源状态的默认设备电源设置.例如,在无人看管的状态下,我的Windows Mobile Professional手机会关闭屏幕上的背光,但会保持声音适配器和GPS接收机的电源打开.这些设置的信息可以在HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Power \ Timeouts \ State \中找到.对于每种电源状态,您都会找到一个键.该键的内容是字符串子键,其名称与设备上的硬件匹配,并且其值与设备的电源状态匹配(因此0x04与D4
匹配,这意味着某些硬件将在匹配状态下以全功率打开) .
防止系统掉电
如果未检测到用户操作,Pocket PC将自动进入其挂起状态.有时,即使用户没有直接与系统进行交互(例如,在使用Windows Media Player收听音乐时),您仍可能需要设备保持其全功率状态.为了防止系统定期关闭电源,请调用SystemIdleTimerReset
().调用此函数可防止达到暂停超时.可以在系统上更改挂起超时,因此您将需要查询挂起值,并确保以小于最小挂起超时值的时间间隔调用SystemIdleTimerReset
.暂停超时值可以通过调用SystemParametersInfo
获取.此函数可用于获取以下三个超时值:
超时值也可以从注册表中检索.在[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Power]位置中查找以下键:
电池状态
Windows Mobile设备中的电池状态可通过本机方法GetSystemPowerStatusEx2()获得.所提供的信息将告诉您设备是否已连接到外部电源以及对主电池和备用电池(如果有)中剩余电量的估计.本机函数以SYSTEM_POWER_STATUS_EX2结构返回其信息,并包含通过托管的SystemState类不可用的信息,例如电池的温度或电池消耗的瞬时电量.返回的电池度量的准确性取决于OEM. OEM也可能决定不收集并返回某些电池指标,在这种情况下,可能会返回xxxx_UNKNOWN值之一.操作系统更新其电池信息之间的最长时间可以在[HKEY_LOCAL_MACHINE \ SYSTEM \ CurrentControlSet \ Control \ Power \ Timeouts \ BatteryPoll]中找到. 在所附的示例程序中,有一个名为"电池状态"的程序,该程序在电池上显示信息.程序顶部显示电池上最重要的数据:其当前容量,是否连接到交流电源,电池温度,电压输出和电池电流(请注意,电流符号会设备充电时更改).
Microsoft.WindowsMobile.Status.
SystemState
类还可用于监视电源状态并接收电池更换通知.从" SystemState"类可获得的信息是较低的分辨率(它以"非常低",“低”,“中”,“高"和"非常高"来描述电池状态,而本机函数以百分比形式返回电池电量). " SystemState"类也不返回有关功耗或电池温度的信息.
保持力量
如果您想确保程序负责任地工作并且不会不必要地消耗电池的电量,那么程序可以做的最好的事情就是在不需要执行任何工作时停止执行工作.听起来像是常识,不是吗?但是,当程序可以通过不执行任何操作来节省电量时,它们会为程序带来不必要的工作量而感到惊讶.我在支持论坛上遇到的最常见的功率消耗模式是连续轮询.此类实现的示例如下:
BeginSomeTimeConsumingTask();
while(!taskComplete)
{
Application.DoEvents();
}
编写上面的代码的目的是在另一个线程上运行一个长时间运行的进程,并等待它在主线程中完成而不影响主线程的响应性.如果主线程没有工作,则CPU不必要地在燃烧循环,以等待另一个线程继续.更好的选择是具有后台任务信号.
问题"迭代检查”
描述
线程需要等待事件发生才能继续执行其余的操作.许多开发人员将创建一个布尔变量,并在其他线程可以继续执行时更改其值.等待线程将这个变量池化,直到它改变为止,然后继续执行其任务.
说明
等待线程不必要地轮询变量并在不完成任何工作的情况下燃烧CPU周期.
解
运行时和操作系统已通过各种同步对象提供了实现此功能的工具.可以使用同步技术来阻塞线程,直到任务完成或另一个线程发出信号通知其完成.程序还可以等待外部事件,或者在某个外部事件(例如,设备已接通电源或正在初始化ActiveSync会话)期间注册自己以启动.对于这些情况,程序可以注册以在事件发生时进行通知或启动.当轮询是查询状态的唯一方法时,请考虑在两次检查之间使线程处于休眠状态. 有关同步文章的讨论应有自己的位置.我在另一篇文章中写了关于它们的文章.我已经在这里.写过关于它们的文章.
示例:NoPolling
举一个简单的例子,我将使用委托和线程池来执行长时间运行的任务.委托是必需的,因为不能从辅助线程更新UI元素,并且可以使用委托来确保UI更新在正确的线程上进行.完整的程序可以在随附的示例代码中找到.
delegate void UpdateStatusDelegate(int progress);
delegate void VoidDelegate();
UpdateStatusDelegate _updateStatus;
VoidDelegate _taskComplete;
WaitCallback _longRunningTask;
public Form1()
{
InitializeComponent();
_longRunningTask = new WaitCallback(LongRunningTask);
_updateStatus = new UpdateStatusDelegate(UpdateStatus);
_taskComplete = new VoidDelegate(TaskComplete);
}
// We cannot update UI elements from secondary threads. However
// the Control.Invoke method can be used to execute a delegate
// on the main thread. If UpdateStatus is called from a secondary
// thread it will automatically call itself through Control.Invoke
// to ensure its work is performed on the primary (UI) thread.
void UpdateStatus(int progress)
{
if (this.InvokeRequired)
BeginInvoke(_updateStatus, new object[] { progress });
else
{
this.txtFeedback.Text = progress.ToString();
pbWorkStatus.Value = progress;
}
}
// The long running task is contained within this method.
// as the task runs it will pass progress updates back to
// the UI through the UpdateStatus method. Upon completion
// of the task a call is made to TaskComplete
void LongRunningTask(object o)
{
try
{
for (int i = 0; i < 100; ++i)
{
Thread.Sleep(100);
UpdateStatus(i);
}
TaskComplete();
}
catch (ThreadAbortException exc)
{
//The task is being cancelled.
}
}
// Since the actions the program takes at completion of the long
// running task touch UI elements the TaskComplete method will
// also call itself (if necessary) through Control.Invoke to
// ensure that it is executing on the primary (UI) thread.
void TaskComplete()
{
if (this.InvokeRequired)
{
this.Invoke(_taskComplete);
}
else
{
pbWorkStatus.Value = 0;
miWork.Enabled = true;
txtFeedback.Text = "Complete";
}
}
// When the user selects the menu item to begin working
// I will disable the work menu item to prevent concurrent
// request and start the long running progress on a secondary
// thread.
private void miWork_Click(object sender, EventArgs e)
{
miWork.Enabled = false;
ThreadPool.QueueUserWorkItem(_longRunningTask);
}
private void miQuit_Click(object sender, EventArgs e)
{
this.Close();
}
问题"不要让设备进入睡眠状态"
描述
程序正在执行长时间运行的任务,不需要用户交互,例如GPS导航(用户可能会看着屏幕但不触摸屏幕).程序运行了一段时间后,屏幕关闭,并中断了用户的体验.
说明
由于用户没有与系统进行交互,因此它会像往常一样进行操作,并且正在关闭设备电源以节省电量.
解
定期调用本机函数" SystemIdleTimerReset()“以防止设备掉电.
示例程序:PreventSleep
程序” PreventSleep"从注册表中读取空闲超时值,并以比最短超时稍短的时间间隔调用" SystemIdleTimeReset".结果,只要" PreventSleep"正在运行,由于缺少用户交互,设备将不会进入睡眠状态. 在代码示例中,在计时器上调用了" SystemIdleTimeReset",因此主线程无需关心维护复位.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Win32;
using Microsoft.Win32;
namespace PreventSleep
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
// Look in the registry to see what the shortest timeout
// period is. Note that Zero is a special value with respect
// to timeouts. It indicates that a timeout will not occur.
// As long as SystemIdleTimeerReset is called on intervals
// that are shorter than the smallest non-zero timeout value
// then the device will not sleep from idleness. This does
// not prevent the device from sleeping due to the power
// button being pressed.
int ShortestTimeoutInterval()
{
int retVal = 1000;
RegistryKey key = Registry.LocalMachine.OpenSubKey(
@"\SYSTEM\CurrentControlSet\Control\Power");
object oBatteryTimeout = key.GetValue("BattPowerOff");
object oACTimeOut = key.GetValue("ExtPowerOff");
object oScreenPowerOff = key.GetValue("ScreenPowerOff");
if (oBatteryTimeout is int)
{
int v = (int)oBatteryTimeout;
if(v>0)
retVal = Math.Min(retVal,v);
}
if (oACTimeOut is int)
{
int v = (int)oACTimeOut;
if(v>0)
retVal = Math.Min(retVal, v);
}
if (oScreenPowerOff is int)
{
int v = (int)oScreenPowerOff;
if(v>0)
retVal = Math.Min(retVal, v);
}
//Since the interval is in seconds and out timer
//operates in milliseconds the value needs to be multiplied
//by 1000 to get the appropriate millisecond value. I've
//multiplied by 900 instead so that I ensure that I call
//SystemIdleTimerReset before the timeout is reached.
return retVal*900;
}
private void Form1_Load(object sender, EventArgs e)
{
// Set the interval on our timer and start the
// timer. It will run for the duration of the
// program
int interval = ShortestTimeoutInterval();
resetTimer.Interval = interval;
resetTimer.Enabled = true;
}
private void miQuit_Click(object sender, EventArgs e)
{
this.Close();
}
// Call the SystemIdleTimerReset method to prevent the
// device from sleeping
private void resetTimer_Tick(object sender, EventArgs e)
{
CoreDLL.SystemIdleTimerReset();
}
}
}
问题"醒来并安静地工作"
描述
您的程序需要在预定的时间唤醒并执行一些工作.
说明
当设备唤醒并且程序开始运行时,将设备置于完全供电模式将不必要地引起用户的注意,或者如果设备出了问题,则可能导致屏幕和按钮接收按键.我们需要在不打开屏幕电源的情况下唤醒设备.用户应该完全不知道设备正在做任何工作.
解
设备唤醒后,程序应立即将Windows Mobile设备置于无人参与模式.在这种模式下,如果用户未使用设备,则设备的屏幕将无法启动,但程序仍可以像设备已完全通电一样运行.程序完成工作后,就可以释放对设备处于无人照管模式的要求,并且可以在用户从未意识到设备已完成任何操作的情况下返回睡眠状态.
示例程序:安静地工作
WorkQuietly允许用户在启动时选择声音文件和时间延迟.选择"运行"菜单选项后,程序将安排使用" CeRunAppAtTime"本机调用重新启动自身,如上一篇文章中所述.按计划启动程序并终止.在选定的时间延迟后,程序将启动并播放声音.播放声音与该程序的名称完全矛盾,但这是向某人证明该程序正在运行的最明显的事情.
这是我修改项目的Main()方法的罕见情况之一.由于调度而启动应用程序时,将传递命令行参数" AppRunAtTime". Main()方法的默认实现不接受命令行参数.找到AppRunAtTime
参数后,我没有加载表单,而是让应用程序播放其声音并退出.
// Schedule the execution of the program and terminate.
// You can either put the device to sleep or leave it at
// full power. In either case the program will run at its
// assigned time, play a sound, and then terminate
private void miRun_Click(object sender, EventArgs e)
{
int waitTime = int.Parse(this.cboStartTime.Text);
DateTime startTime = DateTime.Now.AddSeconds(waitTime);
string targetExecutable =
this.GetType().Assembly.GetModules()[0].FullyQualifiedName;
RunAppAtTime(targetExecutable, startTime);
using (StreamWriter sw = new StreamWriter(targetExecutable + ".soundPath"))
{
sw.Write(txtSoundPath.Text);
sw.Close();
}
this.Close();
}
以下是我修改的Main
方法:
[MTAThread]
static void Main(string[] args)
{
if (args.Length == 0)
Application.Run(new Form1());
else if (args[0].Equals("AppRunAtTime"))
{
string soundPath;
// We started due to a scheduled event
CoreDLL.PowerPolicyNotify(PPNMessage.PPN_UNATTENDEDMODE, -1);
string targetExecutable =
typeof(Form1).Assembly.GetModules()[0].FullyQualifiedName;
StreamWriter argInfo = new StreamWriter(targetExecutable + ".argument.txt");
argInfo.WriteLine(args[0]);
argInfo.Close();
using (StreamReader sr = new StreamReader(targetExecutable + ".soundPath"))
{
soundPath = sr.ReadToEnd();
sr.Close();
}
if (File.Exists(soundPath))
Aygshell.SndPlaySync(soundPath, 0);
CoreDLL.PowerPolicyNotify(PPNMessage.PPN_UNATTENDEDMODE, 0);
}
}
问题"您的程序需要查询电池的电量"
能够查询电池的电量对创建Windows Mobile实用程序以及使程序对可用电量进行负责任的响应非常有用.
示例程序:BatteryStatus
获取电池状态信息的过程非常简单. P/Invoke声明和辅助函数如下所示:
[DllImport("CoreDLL")]
public static extern int GetSystemPowerStatusEx2(
SYSTEM_POWER_STATUS_EX2 statusInfo,
int length,
int getLatest
);
public static SYSTEM_POWER_STATUS_EX2 GetSystemPowerStatus()
{
SYSTEM_POWER_STATUS_EX2 retVal = new SYSTEM_POWER_STATUS_EX2();
int result = GetSystemPowerStatusEx2( retVal, Marshal.SizeOf(retVal) , 0);
return retVal;
}
参数" getLatest"控制是否返回缓存的信息或返回更多的更新信息.缓存的信息通常不超过5秒,因此我认为不需要更新的信息.如果您想确保您的信息始终是最新的,请为getLatest参数传递一个非零值.该示例程序在顶部显示带有图标的最有趣的信息,并在图形下方的列表框中显示该函数返回的所有值.顶部的信息包括剩余的电池电量,电池的电压输出,电池温度,消耗的电流以及电池是否耗尽AC电源.请注意,当电池从充电到放电时,电流的符号可能会在正负极之间变化.
好奇心:我的设备支持哪些电源状态
在搜索其他信息时,我偶然发现了一些有趣的注册表项,从而产生了该程序.使用注册表,该程序将列出您设备的电源状态.选择一种电源状态将使程序通知您设备驱动程序的默认电源状态,以及应该具有除默认状态以外的某些状态的硬件.
示例程序:MyPowerStates
用于此的代码只不过是经过筛选的注册表转储.这是程序主要部分的源代码:
const string BASE_POWER_HIVE = @"System\CurrentControlSet\Control\Power\State";
string[] _powerStateNames = {"Full Power","Power Savings",
"Standby","Sleep Mode",
"Power Off"};
Regex _targetRegistryValue = new Regex("(DEFAULT)|(^.*:$)",
RegexOptions.IgnoreCase);
string[] GetPowerStateList()
{
RegistryKey powerStateKey = Registry.LocalMachine.OpenSubKey(BASE_POWER_HIVE);
return powerStateKey.GetSubKeyNames();
}
string[][] GetPowerStateInfo(string stateName)
{
RegistryKey stateInformationKey =
Registry.LocalMachine.OpenSubKey(String.Format(@"{0}\{1}",
BASE_POWER_HIVE, stateName));
string[] valueList = stateInformationKey.GetValueNames();
List<string[]> StateInfo = new List<string[]>();
for (int i = 0; i < valueList.Length; ++i)
{
string currentValue = valueList[i];
if (_targetRegistryValue.IsMatch(currentValue))
{
StateInfo.Add(new string[] { valueList[i],
_powerStateNames[(int) stateInformationKey.GetValue(currentValue)]});
}
}
return StateInfo.ToArray();
}
void PopulatePowerState()
{
cboPowerState.Items.Clear();
string[] stateList = GetPowerStateList();
List<string> sortList = new List<string>(stateList);
sortList.Sort();
for (int i = 0; i < sortList.Count; ++i)
{
cboPowerState.Items.Add(sortList[i]);
}
}
获取电源更改通知
如果您想接收有关设备电源状态更改的通知,则可以从电源管理器注册通知.这样做需要了解本机同步事件和队列.请参阅文章.NET中与队列的Windows Mobile进程间通信.
加法
如前所述,该文档是一项正在进行中的工作,我决定与他人共享,因为我认为它将对社区有所帮助.在接下来的几周内,将对文档进行编辑并添加示例程序.如果您想看什么,请随时提出请求.请在下面留言.如果您喜欢这篇文章,请对其评分.
资源和参考
API参考
- 电源管理功能
文章和博客条目
图书
历史
- 系统状态
许可
本文以及所有相关的源代码和文件均已获得The Code Project Open License (CPOL)的许可。
.NET2.0 C#2.0 C#3.0 WinMobile5 VS2008 C# WinMobile .NET Visual-Studio Dev Intermediate Advanced WinMobile6 新闻 翻译