How to get value of advanced power settings

Some times you may need to get value of advanced power settings in your application. For example you may want to know after how much idle time, the system will hibernate of sleep. Here in this post I’ll show how you can get those values in C# using different solutions. For example we will get value of Hibernate after setting.

You can get value of advanced power settings values using Windows API, Registry, and WMI. The most important common information for all solutions is some GUID values:

  • Power Scheme GUID: Identifier of power plan
  • Subgroup GUID: Identifier of a group of the settings
  • Power Setting GUID: Identifier of the setting

Advanced power settings

For example to get value of Hibernate After, you need following GUIDs:

  • GUID of Active Plan (You should first find it.)
  • GUID of Sleep Sub Group : 238c9fa8-0aad-41ed-83f4-97be242c8f20
  • GUID of Hibernate After Setting: 9d7815a6-7ee4-497e-8888-515a05f02364

But how can you find GUID of active plan, sub groups and settings? Any solution which you use, you need to first find GUID of Active Plan programmatically. But other GUIDs you can use constant values. For example, you can run this command in command window having admin privilege:

powercfg -QUERY >c:\poweroptions.txt

Then if you open the file, you will see a list of sub groups and settings and their values:

...
Subgroup GUID: 238c9fa8-0aad-41ed-83f4-97be242c8f20  (Sleep)
  GUID Alias: SUB_SLEEP
    ...
    Power Setting GUID: 9d7815a6-7ee4-497e-8888-515a05f02364  (Hibernate after)
      GUID Alias: HIBERNATEIDLE
      Minimum Possible Setting: 0x00000000
      Maximum Possible Setting: 0xffffffff
      Possible Settings increment: 0x00000001
      Possible Settings units: Seconds
    Current AC Power Setting Index: 0x00002a30
    Current DC Power Setting Index: 0x00002a30
...

So using the result you can find sub groups GUID and settings GUID. To find more about powercfg command you can use powercfg /?.

Using Windows API

There are a couple of power management functions which allows us to read and change advanced power settings. You can use PowerGetActiveScheme function to get the active power plan, then you can use PowerReadACValue to get the value which you need.

To do so, first declare:

private static Guid GUID_SLEEP_SUBGROUP =
    new Guid("238c9fa8-0aad-41ed-83f4-97be242c8f20");
private static Guid GUID_HIBERNATEIDLE =
    new Guid("9d7815a6-7ee4-497e-8888-515a05f02364");

[DllImport("powrprof.dll")]
static extern uint PowerGetActiveScheme(
    IntPtr UserRootPowerKey,
    ref IntPtr ActivePolicyGuid);

[DllImport("powrprof.dll")]
static extern uint PowerReadACValue(
    IntPtr RootPowerKey,
    ref Guid SchemeGuid,
    ref Guid SubGroupOfPowerSettingGuid,
    ref Guid PowerSettingGuid,
    ref int Type,
    ref int Buffer,
    ref uint BufferSize);

Then find the value this way:

var activePolicyGuidPTR = IntPtr.Zero;
PowerGetActiveScheme(IntPtr.Zero, ref activePolicyGuidPTR);

var activePolicyGuid = Marshal.PtrToStructure<Guid>(activePolicyGuidPTR);
var type = 0;
var value = 0;
var valueSize = 4u;
PowerReadACValue(IntPtr.Zero, ref activePolicyGuid,
    ref GUID_SLEEP_SUBGROUP, ref GUID_HIBERNATEIDLE,
    ref type, ref value, ref valueSize);

var message = $"Hibernate after {value} seconds.";

Using Registry

HKEY_LOCAL_MACHINE
  SOFTWARE
    Microsoft
      Windows
        CurrentVersion
          explorer
            ControlPanel
              NameSpace 
                {025A5937-A6BE-4686-A844-36FE4BEC8B6D}

Then you can find value of ProvAcSettingIndex from the following key, if the value has been changed:

HKEY_LOCAL_MACHINE
  SYSTEM
    CurrentControlSet
      Control
        Power
          PowerSettings
            <Value of sub group GUID>
              <Value of setting GUID>
                DefaultPowerSchemeValues
                  <VALUE OF ACTIVE PLAN>

Or if the value has it’s default value, you can find it here:

HKEY_LOCAL_MACHINE
  SYSTEM
    CurrentControlSet
      Control
        Power
          User 
            PowerSchemes
              <VALUE OF ACTIVE PLAN>
                <Value of subgroup GUID>
                  <Value of setting GUID>

So you should first check for the existence of the custom value, then if it doesn’t exists, check the default value. Here is the code:

var seconds = 0;

var HKLM = Microsoft.Win32.Registry.LocalMachine;
var activePlanKeyName = @"SOFTWARE\Microsoft\Windows\CurrentVersion" +
    @"\Explorer\ControlPanel\NameSpace\" +
    "{025A5937-A6BE-4686-A844-36FE4BEC8B6D}";
var activePlan = HKLM.OpenSubKey(activePlanKeyName).GetValue("PreferredPlan");

var sleepGroup = "238c9fa8-0aad-41ed-83f4-97be242c8f20";
var hibernateAfter = "9d7815a6-7ee4-497e-8888-515a05f02364";
var userCustomKeyName = $@"SYSTEM\CurrentControlSet\Control\Power\User\PowerSchemes\" +
    $@"{activePlan}\{sleepGroup}\{hibernateAfter}";
var defaultKeyName = $@"SYSTEM\CurrentControlSet\Control\Power\PowerSettings\" +
    $@"{sleepGroup}\{hibernateAfter}\DefaultPowerSchemeValues\{activePlan}";
var key = HKLM.OpenSubKey(userCustomKeyName, false);
if (key != null)
{
    var result = key.GetValue("ACSettingIndex");
    if (result != null)
        seconds = (int)result;
}
else
{
    key = HKLM.OpenSubKey(defaultKeyName, false);
    seconds = (int)key.GetValue("ProvAcSettingIndex");
}
var message = $"Hibernate after {seconds} seconds.";

Using WMI

To use WMI solution, you first need to add reference to System.Management.dll and add using System.Management; then using the following code, we first find active plan GUID using Win32_PowerPlan, then using Win32_PowerSettingDataIndex we can get the value:

var scope = @"root\cimv2\power";
var query = "SELECT * FROM Win32_PowerPlan WHERE IsActive = True";
var searcher = new ManagementObjectSearcher(scope, query);
var activePlan = searcher.Get().Cast<ManagementObject>().First();
var activePlanId = ((string)activePlan.GetPropertyValue("InstanceId")).Split('\\')[1];
var hibernateAfter = activePlan.GetRelated("Win32_PowerSettingDataIndex").Cast<ManagementObject>()
    .Where(x => (string)x.GetPropertyValue("InstanceId") ==
    $@"Microsoft:PowerSettingDataIndex\{activePlanId}\AC\{{9d7815a6-7ee4-497e-8888-515a05f02364}}"
    ).First();
var value = (uint)hibernateAfter.GetPropertyValue("SettingIndexValue");
var message = $"Hibernate after {value} seconds.";

You May Also Like

About the Author: Reza Aghaei

I’ve been a .NET developer since 2004. During these years, as a developer, technical lead and architect, I’ve helped organizations and development teams in design and development of different kind of applications including LOB applications, Web and Windows application frameworks and RAD tools. As a teacher and mentor, I’ve trained tens of developers in C#, ASP.NET MVC and Windows Forms. As an interviewer I’ve helped organizations to assess and hire tens of qualified developers. I really enjoy learning new things, problem solving, knowledge sharing and helping other developers. I'm usually active in .NET related tags in stackoverflow to answer community questions. I also share technical blog posts in my blog as well as sharing sample codes in GitHub.

Leave a Reply

Your email address will not be published. Required fields are marked *