现在的位置: 首页 > 综合 > 正文

Windows XP电源管理及注册表分析

2011年07月09日 ⁄ 综合 ⁄ 共 6334字 ⁄ 字号 评论关闭

  这两天写一个关于电脑电源选项的管理程序,可以使电脑能更少的用电。最开始想的是通过注册表来实现,然后搜索关键字就为“电源选项 注册表”,然后国庆的前面两天一直是在忙于“电源选项”和“注册表”之间的联系,花了一天的时间来分析关系,然后另一天的时间来架构和编码。郁闷的是,最后做出来程序可以操作电源选项的那部分注册表,但是就是电源不按照设置的工作,也没有查出原因来,我猜测可能是分析出来电源注册表值之间关系不对,或是注册表更新的问题。

  没办法,这个管理程序要急于做出来,于是厚着脸皮去请教同学了,他先过来搜索的是“VC 注册表 更新”(受我之前的想法),不过还是没有解决问题,于是搜索“VC 电源选项”然后找到了PPOWER_POLICY结构体,然后问题就解决了。哈哈...虽说这个程序比较2。进入正题,GO!

注册表:

  注册表中电源选项的关键字为“PowerCfg”,以为Windows XP SP3的系统为例,注册表中有“PowerCfg”的位置有HKEY_CURRENT_USER\Control Panel\PowerCfgHKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\ControlsFolder\PowerCfgHKEY_USERS\.DEFAULT\Control Panel\PowerCfgHKEY_USERS\S-1-5-18\Control Panel\PowerCfgHKEY_USERS\S-1-5-19\Control Panel\PowerCfgHKEY_USERS\S-1-5-20\Control Panel\PowerCfgHKEY_USERS\S-1-5-21-1292428093-1123561945-682003330-1003\Control Panel\PowerCfgHKEY_USERS\S-1-5-21-1292428093-1123561945-682003330-1003\Software\Microsoft\Windows\CurrentVersion\Applets\Regedit。
  最后通过测试分析发现电源选项中注册表①和②最为重要,①中项“PowerPolicies”为电源选项中配置的方案列表,“CurrentPowerPolicy”为当前系统使用的方案。如下:

  [HKEY_CURRENT_USER\Control Panel\PowerCfg\PowerPolicies\0]
  "Name"="家用/办公桌"
  "Description"="此种模式适用于大多数家用和桌面计算机,这些计算机可在任何时候插入使用。"
  "Policies"=hex:01,00,00,00,02,00,00,00,01,00,00,00,00,00,00,00,02,00,00,00,05,\
          00,00,00,00,00,00,00,[b0,04],00,00,78,00,00,00,32,32,03,02,02,00,00,00,02,00,\
          00,00,00,00,18,77,2e,f2,07,00,[3c,00],00,00,3c,00,00,00,[00,00],00,00,b4,00,00,\
          00,00,00,64,64,64,64,93,7c

  在Policies中存储的REG_BINARY格式(16进制格式?),分析发现第一个[]中(28/29位置,0开始)表示“系统待机”,第二个[]中(56/57位置)表示“关闭监视器”,第三个[](64/65位置)表示“关闭硬盘”。时间是按秒数的16进制保存的,比如[b0,04]表示16进制的[0x04b0],换算成十进制为1200,表示20分钟,"从不"对应的为[00,00]。
   ②中“PowerPolicies”和“ProcessorPolicies”列举的是出现过的电源选项(包括自定义),这里解释一下,当你通过“控制面板”→“电源选项”新建的方案这里会记录,即使你删除之后这里还是会存在(存储的数值没有分析过什麽含义:)),①的记录则会删除。“LastID”表示历史记录中出现过的方案数目,这个值和①也会有关系的。

 

API函数:(来源参考资料1)

  Windows的电源管理可以指定多种Schemes(配置),并指定当前应用何种Scheme。对于每一种Scheme包含使用电池时的配置和使用电源时的配置。

  1、枚举系统所有的Power
Schemes

 

View Code

BOOLEAN EnumPwrSchemes(
PWRSCHEMESENUMPROC lpfnPwrSchemesEnumProc,
LPARAM lParam
);


  自定义的枚举Callback函数类型是:

 

View Code

Typedef BOOLEAN (CALLBACK* PWRSCHEMESENUMPROC)(
UINT uiIndex, // power scheme index
DWORD dwName, // size of the sName string, in bytes
LPTSTR sName, // name of the power scheme
DWORD dwDesc, // size of the sDesc string, in bytes
LPTSTR sDesc, // description string
PPOWER_POLICY pp, // receives the power policy
LPARAM lParam // user-defined value
);


  其中:The sName and sDesc parameters are null-terminated
strings; they are Unicode strings on Windows 2000/XP and ANSI strings on
Windows Me/98/95.

  2、得到当前正在使用的Power
Scheme

 

View Code

BOOLEAN GetActivePwrScheme(
PUINT puiID/*得到Power Scheme索引*/
);
BOOLEAN ReadPwrScheme(
UINT uiID,/*根据索引读取Scheme*/
PPOWER_POLICY pPowerPolicy
);

或:

 

View Code

BOOLEAN GetCurrentPowerPolicies(
PGLOBAL_POWER_POLICY pGlobalPowerPolicy,
PPOWER_POLICY pPowerPolicy
);


  3、判断当前计算机是连接在电源上还是电池上:

 

View Code

SYSTEM_POWER_STATUS sps;
GetSystemPowerStatus(&sps);
if (sps.ACLineStatus)
{
// 连接电源
}
else
{
// 连接电池
}


  4、通过Windows的电源管理功能,我们可以得到(设定)显示器的关闭时间、硬盘停转时间、系统休眠时间。设定时间的API是:

 

View Code

BOOLEAN WritePwrScheme(
PUINT puiID,/*Power Scheme索引*/
LPTSTR lpszName,
LPTSTR lpszDescription,
PPOWER_POLICY pPowerPolicy
);

显示器关闭时间:POWER_POLICY.user.VideoTimeoutAc(电源)或POWER_POLICY.user.VideoTimeoutDc(电池)

  硬盘停转时间:POWER_POLICY.user.SpindownTimeoutAc(电源)或POWER_POLICY.user.SpindownTimeoutDc(电池)

  系统StandbyHibernate时间稍微复杂一点,以下以连接在电源(AC)为例,得到时间的逻辑为:

 

View Code

if (POWER_POLICY.user.IdleAc.Action == PowerActionHibernate)
{
Standby 时间 = 0;
Hibernate 时间 = POWER_POLICY.user.IdleTimeoutAc;
}
else
{
Standby 时间 = POWER_POLICY.user.IdleTimeoutAc;
Hibernate 时间 = POWER_POLICY.user.IdleTimeoutAc+POWER_POLICY.mach.DozeS4TimeoutAc;
}
// 设定的逻辑为(时间值为0表示从不Standby或从不Hibernate):
if (!Standby时间 && !Hibernate时间)
{
POWER_POLICY.user.IdleTimeoutAc = 0;
POWER_POLICY.mach.DozeS4TimeoutAc = 0;
POWER_POLICY.user.IdleAc.Action = PowerActionNone;
}
else if (Hibernate时间 && !Standby时间)
{
POWER_POLICY.user.IdleTimeoutAc = Hibernate时间;
POWER_POLICY.mach.DozeS4TimeoutAc = 0;
POWER_POLICY.user.IdleAc.Action = PowerActionHibernate;
}
else
{
POWER_POLICY.user.IdleTimeoutAc = Standby时间;
POWER_POLICY.mach.DozeS4TimeoutAc = 0;
if (Hibernate时间 > Standby时间)
POWER_POLICY.mach.DozeS4TimeoutAc = Hibernate时间 - Standby时间;
POWER_POLICY.user.IdleAc.Action = PowerActionSleep;
}

5、还可以指定是否允许休眠,从待机状态中回复过来是否需要密码等

  5.1、检查系统是否允许Hibernate

  BOOLEAN IsPwrHibernateAllowed(void);

  5.2、禁止系统Hibernate

 

View Code

BOOL bEnable = FALSE;
CallNtPowerInformation(SystemReserveHiberFile, &bEnable, sizeof(BOOLEAN), NULL, NULL);

  这里注意:typedef
BYTE BOOLEAN

  5.3、允许系统Hibernate

 

View Code

BOOL bEnable = TRUE;
CallNtPowerInformation(SystemReserveHiberFile, &bEnable, sizeof(BOOLEAN), NULL, NULL);

  还有一种最简单的办法是直接执行系统提供的程序windows\system32\powercfg.exe /hibernate {on|off}

6.还有一种更简便的方法得到(设定)系统当前的屏幕关闭时间;待机、休眠时间等,那就是调用CallNtPowerInformation:

 

View Code

NTSTATUS CallNtPowerInformation(
POWER_INFORMATION_LEVEL InformationLevel,
PVOID lpInputBuffer,
ULONG nInputBufferSize,
PVOID lpOutputBuffer,
ULONG nOutputBufferSize
);

  其中InformationLevel设为SystemPowerPolicyAc(连接电源)或SystemPowerPolicyDc(使用电池)

  如:

  SYSTEM_POWER_POLICY spp
= {0};

  CallNtPowerInformation(SystemPowerPolicyAc, NULL, 0, &spp, sizeof(spp)); //get power information

  //IdleTimeout: Time that the level of system
activity must remain below the idle detection threshold before the system idle
timer expires, in seconds.

  //Idle: A POWER_ACTION_POLICY structure that defines the system
power action to initiate when the system idle timer expires.

  spp.IdleTimeout = ?;

  //DozeS4Timeout: Time to wait between entering the
suspend state and entering the hibernate sleeping state, in seconds. A value of
zero indicates never hibernate.

  spp.DoseS4Timeout = ?;

//SpindownTimeout: Time before power to fixed disk
drives is turned off, in seconds.

  spp.SpindownTimeout = ?;

  //VideoTimeout: Time before the display is
turned off, in seconds.

  spp.VideoTimeout = ?;

  CallNtPowerInformation(SystemPowerPolicyAc, &spp, sizeof(spp), NULL, 0); //set new power information

7.也可以通过WMI来设置,但需注意WMI版本是否支持:(如以下vbscript)

Set objService =
GetObject("winmgmts:\\.\root\wmi")

Set objMonSet =
objService.InstancesOf("WmiMonitorBrightnessMethods")

For Each objMon In
objMonSet

objMon.WmiSetBrightness
10, 90

Next

8.另需注意:
  
调用SetActivePwrScheme()ReadPwrScheme()时,若传递的Scheme
ID
不存在,则会在注册表(HKEY_CURRENT_USER\Control
Panel\PowerCfg\PowerPolicies\
)下创建这个ID,但内容为空,而这会导致电源管理遍历函数EnumPwrSchemes()不能正常工作(读不到该ID后的power
scheme
);VISTA上的对应函数(PowerGetActiveScheme/PowerReadxxx)就没发现这样的问题。 

 

补充:

POWER_POLICY结构体的介绍http://msdn.microsoft.com/zh-cn/aa372709  

POWER_POLICY结构体自己的分析:IdleTimeOut 系统待机VideoTimeOut 关闭监视器SpindownTimeout 关闭硬盘AC 外接电源DC 电池

 

总结:分析问题首先要站在很高比较全面的角度去考虑,然后逐步向下,各个击破。不能一开始就从一小部分入手,否则很容易进入盲区,然后自己在里面走迷宫。

抱歉!评论已关闭.