In this Vista Goodies article, I'll demonstrate how to monitor the computer's power status using new notifications that were added to Vista. For apps that may be CPU- or graphics-intensive � such as audio encoders, games, and media players � the ability to monitor the power status lets them be intelligent about power consumption when running on laptops. For example, a media player might automatically stop playing when the battery level falls below 15%, so the user will have plenty of time to attach a power cord, and won't have to scramble to close or stop the player to preserve what little power is left.
在vista小技巧一文中,我会通过vista中增加的新通知机制展示如何监控电脑的能源状态。对APP来说CPU或是图形增强比如解码器,游戏和多媒体播放器更聪明的获知当前电力消耗。
This article is written for the RTM version of Vista, using Visual Studio 2005, WTL 7.5, and the Windows SDK. See the introduction in the first Vista Goodies article for more information on where you can download those components.
文章基于发布版vista,使用Visual Studio 2005, WTL7.5, 和windows SDK。从你能下载到资料的地方阅读第一篇Vista小技巧获得更多信息。
This article's sample project is a dialog-based app that shows some simple animation. It monitors the computer's power status, updates the display to reflect the current status, and turns off the animation in situations where power conservation is important. For example, here is the dialog showing that the computer is running on AC power:
文章示例工程是通过基于对话框的AP显示简单信息. 它能监控到电脑的能源状态,即时更新显示当前的能源消耗状态,并关闭动画的模式下节能是最重要的.比如,这里有一个对话框来显示当前电脑运行在AC供电模式下.
The "Hello, Bob!" text changes color every second in this case, since the computer isn't in a low-power situation and it's OK to use animation.
“Hello, Bob!”文本在这案例中每秒都改变颜色,如果电脑不是在低能源状态和适当使用动画.
Power Schemes and Power Sources in Vista/能源方案和vista能源资料
Vista defines three default power schemes, named Power saver, Balanced, and High performance. Each scheme is a pre-set group of settings that control things like hard disk spin-down time, the maximum CPU speed to use, and so on. You can choose a power scheme using the battery tray icon or the Power Options control panel applet. Here is the tray selector with the Power saver scheme selected:
Vista定义了三个默认的能源方案,命名为:节能方案,均衡方案和高效方案。每个方案是一组设置,控制设定项硬盘降速,最高CPU使用率等等。你可通过点选电池图标或者控制面板中电力选项来选择一个能源方案. 这里是一个打开的节能方案托盘图标:
Vista also has some settings that can be different when the computer is using different power sources: batteries versus AC power. You can, for example, set the monitor to turn off after 3 minutes on batteries, or 15 minutes on AC power. Vista also monitors the battery power remaining, which is expressed as a percentage from 1 to 100.
当电脑使用不同的能源供电方式时,Vista的能源方案也有一些设定不同:电池和能电源。 例如,你可以设定在电池供电模式下, 3分钟后关闭显示器,或者在交流供电下15分钟后关闭显示器,vista也检测电池剩余电量,用百分比表示.
Registering for Power Notifications/登记能源通知
Apps can register to be notified of changes to the power scheme, power source, or battery power. The two APIs involved are RegisterPowerSettingNotification() and UnregisterPowerSettingNotification(). The prototype for RegisterPowerSettingNotification() is:
AP可以注册能源方案变化,能源或者电池供电改变的通知,这两个API是RegisterPowerSettingNotification() 和 UnregisterPowerSettingNotification(),原型如下:
Collapse/ 缩进
HPOWERNOTIFY RegisterPowerSettingNotification(
HANDLE hRecipient, LPCGUID PowerSettingGuid, DWORD Flags);
hRecipient is a handle to the object that wants to receive notifications; in our case it's our dialog's HWND. PowerSettingGuid is a GUID that indicates which event we want to be notified of. Flags indicate what type of handle hRecipient is; in this sample code, the handle will always be an HWND, so we'll pass DEVICE_NOTIFY_WINDOW_HANDLE for Flags.
hRecipient 是指向用来接收通知的一个句柄,在我们的程式中,是对话框的窗口句柄,PowerSettingGuid是一个用来说明被那个事件通知的GUID。Flags声明hRecipient属于类型;在这个样码中,hRecipient是窗口句柄,因此我们传递DEVICE_NOTIFY_WINDOW_HANDLE作为flag。
The relevant GUIDs for PowerSettingGuid are:和PowerSettingGuid有关GUID
GUID_POWERSCHEME_PERSONALITY: register for changes in the power scheme
GUID_ACDC_POWER_SOURCE: register for changes in the power source
GUID_BATTERY_PERCENTAGE_REMAINING: register for changes in the battery power GUID_POWERSCHEME_PERSONALITY:注册能源方案改变变化
GUID_ACDC_POWER_SOURCE:注册电源变化通知
GUID_BATTERY_PERCENTAGE_REMAINING:注册电池能源百分比变化
RegisterPowerSettingNotification() returns an HPOWERNOTIFY, or NULL if an invalid parameter was passed. The HPOWERNOTIFY is only used when unregistering; the actual notifications occur through window messages.
RegisterPowerSettingNotification()返回一个句柄HPOWERNOTIFY,或者若传递一个无效参数的话返回空。句柄HPOWERNOTIFY仅被用在解除注册时;通过windows消息发送这些通知。
How the Sample App Registers /示例注册演示
CMainDlg has three HPOWERNOTIFY members:
CMainDlg有三个HPOWERNOTIFY成员
Collapse/缩进
HPOWERNOTIFY m_hPowerSchemeNotify, m_hPowerSourceNotify,
m_hBatteryPowerNotify;
OnInitDialog() calls RegisterPowerSettingNotification() once for each type of notification. For example, this
code registers for notifications about power scheme changes:
OnInitDialog()呼叫RegisterPowerSettingNotification()一次对每种类型的通知。如:这段代码主次通知能源方案变化。
Collapse /缩进
m_hPowerSchemeNotify = RegisterPowerSettingNotification (
m_hWnd, &GUID_POWERSCHEME_PERSONALITY,
DEVICE_NOTIFY_WINDOW_HANDLE );
if ( NULL == m_hPowerSchemeNotify )
ATLTRACE("Failed to register for notification of power scheme changes!\n");
If RegisterPowerSettingNotification() fails, it's not a critical error; the app just won't be notified about that particular event.
如果RegisterPowerSettingNotification()失败,它不是一个关键错误;APP仅仅不被通知有特定的事件发生.
Handling Power Notifications/处理能源通知
When an app needs to be notified of a power change, the system sends it a WM_POWERBROADCAST message. WM_POWERBROADCAST is not a new message, but in Vista there is a new event code PBT_POWERSETTINGCHANGE and an associated data structure POWERBROADCAST_SETTING. When a PBT_POWERSETTINGCHANGE notification is sent, the message's lParam points to a POWERBROADCAST_SETTING struct, which looks like this:
当一个程式需要被通知能源变化时,系统发送给他一个消息:WM_POWERBROADCAST. WM_POWERBROADCAST不是一个新的的消息,但在Vista中,这有一个新的事件代码PBT_POWERSETTINGCHANGE和一个关联的数据结构POWERBROADCAST_SETTING.当发送一个PBT_POWERSETTINGCHANGE通知,这个消息的长参数指向POWERBROADCAST_SETTING结构,例如这样:
Collapse缩进
typedef struct {
GUID PowerSetting;
DWORD DataLength;
UCHAR Data[1];
} POWERBROADCAST_SETTING;
PowerSetting is a GUID that indicates what type of event occurred. The possible values for this member are the same GUIDs that are passed to RegisterPowerSettingNotification(). The rest of the struct is a variable-length chunk of data that contains the details of the event. This data varies among the different events:
PowerSetting是一个GUID,用来指出哪些类型的事件发生。此成员可能值是传递给RegisterPowerSettingNotification()相同的GUID。该结构其余部分是一个可变长度的数据块,包含了发生事件的详细细节,这个数据变量在不同的事件中:
PowerSetting value
Data description
GUID_POWERSCHEME_PERSONALITY
A GUID that indicates the active power scheme:
GUID_MAX_POWER_SAVINGS: the Power saver scheme
GUID_MIN_POWER_SAVINGS: the High performance scheme
GUID_TYPICAL_POWER_SAVINGS: the Balanced scheme
GUID_ACDC_POWER_SOURCE
An int that indicates the power source: 0 for AC power, 1 for batteries, or 2 for short-term batteries (for
m_cPowerScheme.SetWindowText ( _T("Power saver") );
}
else if ( GUID_MIN_POWER_SAVINGS == newScheme )
{
// New scheme: min power savings (max perf)
m_eCurrPowerScheme = pwrMaxPerf;
m_cPowerScheme.SetWindowText ( _T("Max performance") );
}
else if ( GUID_TYPICAL_POWER_SAVINGS == newScheme )
{
// New scheme: balanced
m_eCurrPowerScheme = pwrBalanced;
m_cPowerScheme.SetWindowText ( _T("Balanced") );
}
else
{
// Unrecognized scheme, we'll treat this like balanced
m_eCurrPowerScheme = pwrBalanced;
m_cPowerScheme.SetWindowText ( _T("Balanced") );
}
}
For power source notifications, we determine whether the new source is batteries or AC power:
对于电源通知,我们测定新的电源是电池还是AC。
Collapse
else if ( sizeof(int) == pps->DataLength &&
pps->PowerSetting == GUID_ACDC_POWER_SOURCE )
{
// This is a power source change notification
int nPowerSrc = *(int*)(DWORD_PTR) pps->Data;
m_bOnBattery = (0 != nPowerSrc);
m_cPowerSource.SetWindowText ( m_bOnBattery ? _T("Battery") :
_T("AC power") );
}
Finally, for battery power notifications, we save the new percentage:
最后,对电池能源通知,我们保存新的百分比。
Collapse
else if ( sizeof(int) == pps->DataLength &&
pps->PowerSetting == GUID_BATTERY_PERCENTAGE_REMAINING )
{
// This is a battery power notification
int nPercentLeft = *(int*)(DWORD_PTR) pps->Data;
CString sPercentLeft;
sPercentLeft.Format ( _T("%d"), nPercentLeft );
m_cBatteryPower.SetWindowText ( sPercentLeft );
m_nBatteryPower = nPercentLeft;
}
Now that we've updated the static text controls to reflect the new power state, we determine whether to turn the animation on or off. The app's logic is this:
现在我们更新静态文本控件反映新的电源状态,我们测定是否打开动画。应用程路逻辑如下:
Turn animation on if:
The current scheme is High performance, or
The current scheme is Balanced and the computer is not on batteries. 打开动画条件
-当前方案是高效方案或
-当前方案是均衡方案,并电脑非电池供电
Turn animation off if:
The current scheme is Balanced and the computer is on batteries, or
The current scheme is Power saver, or
The computer is on batteries and the battery power is 20% or less (no matter what the current scheme is). 关闭动画条件
当前方案是均衡方案,并且电脑是电池供电或
当前方案是节能方案或
电脑是电池供电且电池电量是小于等于20%(无论任何方案)
Collapse
bool bUseAnimation =
(pwrMaxPerf == m_eCurrPowerScheme) ||
(pwrBalanced == m_eCurrPowerScheme && !m_bOnBattery);
if ( m_bOnBattery && m_cBatteryPower <= 20 )
bUseAnimation = false;
// If the animation setting has changed, save the new setting
// and redraw the message area.
if ( bUseAnimation != m_bUseAnimation )
{
m_bUseAnimation = bUseAnimation;
m_cMessage.RedrawWindow();
}
return TRUE; // allow all power actions
}
The m_bAnimation flag is then used elsewhere to determine how to draw the "Hello, Bob!" message. Here's how the dialog looks with animation on and off, respectively:
m_bAnimation后来被用到设定显示文本“hello,bob”信息.这里是动画关闭和打开.分别如下:
Conclusion
总结
For CPU-intensive apps, being aware of the computer's power status can be really nice for your users. For example, a CD burning app could warn the user if the battery is too low, or a download manager could stop downloading in low-power situations to prevent the wireless network card from using up power. Little touches like that can give your apps a nice edge over others when running on Vista.
对CPU密集使用的AP,对于你的用户来讲能够察觉到电脑的能源状况是很棒的事.例如CD烧录AP能通知用户电池电量低,或者在电量低时,下载软体能够停止下载,防止无限网卡过度使用电量。你的应用程序在Vista上运行后具备这样的优势,产生贴心的感觉,就是你的软件比别人好.