Vanara/System/PowerManager.cs

744 lines
30 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using Vanara.Collections;
using Vanara.Extensions;
using Vanara.InteropServices;
using Vanara.PInvoke;
using static Vanara.PInvoke.Kernel32;
using static Vanara.PInvoke.PowrProf;
namespace Vanara.Diagnostics
{
/// <summary>Indicates the status of the battery.</summary>
public enum BatteryStatus
{
/// <summary>The battery or battery controller is not present.</summary>
NotPresent,
/// <summary>The battery is discharging.</summary>
Discharging,
/// <summary>The battery is idle.</summary>
Idle,
/// <summary>The battery is charging.</summary>
Charging
}
/// <summary>Specifies the status of battery saver.</summary>
public enum EnergySaverStatus
{
/// <summary>Battery saver is off permanently or the device is plugged in.</summary>
Disabled,
/// <summary>Battery saver is off now, but ready to turn on automatically.</summary>
Off,
/// <summary>Battery saver is on. Save energy where possible.</summary>
On
}
/// <summary>Specifies the power capabilities of a device.</summary>
[Flags]
public enum PowerCapabilities
{
/// <summary>There is a system power button.</summary>
PowerButtonPresent = 1 << 0,
/// <summary>There is a system sleep button.</summary>
SleepButtonPresent = 1 << 1,
/// <summary>There is a lid switch.</summary>
LidPresent = 1 << 2,
/// <summary>The operating system supports sleep state S1.</summary>
SystemS1 = 1 << 3,
/// <summary>The operating system supports sleep state S2.</summary>
SystemS2 = 1 << 4,
/// <summary>The operating system supports sleep state S3.</summary>
SystemS3 = 1 << 5,
/// <summary>The operating system supports sleep state S4 (hibernation).</summary>
SystemS4 = 1 << 6,
/// <summary>The operating system supports power off state S5 (soft off).</summary>
SystemS5 = 1 << 7,
/// <summary>The system hibernation file is present.</summary>
HiberFilePresent = 1 << 8,
/// <summary>The system supports wake capabilities.</summary>
FullWake = 1 << 9,
/// <summary>The system supports video display dimming capabilities.</summary>
VideoDimPresent = 1 << 10,
/// <summary>The system supports APM BIOS power management features.</summary>
ApmPresent = 1 << 11,
/// <summary>There is an uninterruptible power supply (UPS).</summary>
UpsPresent = 1 << 12,
/// <summary>The system supports thermal zones.</summary>
ThermalControl = 1 << 13,
/// <summary>The system supports processor throttling.</summary>
ProcessorThrottle = 1 << 14,
/// <summary>The system supports the hybrid sleep state.</summary>
FastSystemS4 = 1 << 15,
/// <summary>
/// The system supports fast startup (aka: hiberboot, hybrid boot, or hybrid shutdown) which is a setting that helps your PC start up
/// faster after shutdown.
/// </summary>
Hiberboot = 1 << 16,
/// <summary>
/// The platform has support for ACPI wake alarm devices. For more details on wake alarm devices, please see the ACPI specification
/// section 9.18.
/// </summary>
WakeAlarmPresent = 1 << 17,
/// <summary>The system supports the S0 low power idle model.</summary>
AoAc = 1 << 18,
/// <summary>The system supports allowing the removal of power to fixed disk devices.</summary>
DiskSpinDown = 1 << 19,
/// <summary/>
AoAcConnectivitySupported = 1 << 20,
/// <summary>There are one or more batteries in the system.</summary>
SystemBatteriesPresent = 1 << 21,
/// <summary>The system batteries are short-term. Short-term batteries are used in uninterruptible power supplies (UPS).</summary>
BatteriesAreShortTerm = 1 << 22
}
/// <summary>Represents the device's power supply status.</summary>
public enum PowerSupplyStatus
{
/// <summary>The device has no power supply.</summary>
NotPresent,
/// <summary>The device has an inadequate power supply.</summary>
Inadequate,
/// <summary>The device has an adequate power supply.</summary>
Adequate
}
/// <summary>
/// Provides access to information about a device's battery and power supply status and configuration. This extends the capabilities
/// Windows.System.Power.PowerManager to include more detail, schemes and devices.
/// </summary>
public static class PowerManager
{
/*
public static event EventHandler BatteryStatusChanged;
public static event EventHandler EnergySaverStatusChanged;
public static event EventHandler PowerSupplyStatusChanged;
public static event EventHandler RemainingChargePercentChanged;
public static event EventHandler RemainingDischargeTimeChanged;
*/
/// <summary>Gets the device's battery status.</summary>
/// <value>Returns a <see cref="BatteryStatus"/> value.</value>
public static BatteryStatus BatteryStatus => GetStatus().BatteryFlag switch
{
BATTERY_STATUS.BATTERY_CHARGING => BatteryStatus.Charging,
BATTERY_STATUS.BATTERY_NONE => BatteryStatus.NotPresent,
_ => GetStatus().ACLineStatus == AC_STATUS.AC_OFFLINE ? BatteryStatus.Discharging : BatteryStatus.Idle,
};
/// <summary>Gets flags indicating the system's power capabilities.</summary>
/// <value>Returns a <see cref="PowerCapabilities"/> value.</value>
public static PowerCapabilities DeviceCapabilities
{
get
{
var c = GetCapabilities();
PowerCapabilities ret = 0;
if (c.PowerButtonPresent) ret |= PowerCapabilities.PowerButtonPresent;
if (c.SleepButtonPresent) ret |= PowerCapabilities.SleepButtonPresent;
if (c.LidPresent) ret |= PowerCapabilities.LidPresent;
if (c.SystemS1) ret |= PowerCapabilities.SystemS1;
if (c.SystemS2) ret |= PowerCapabilities.SystemS2;
if (c.SystemS3) ret |= PowerCapabilities.SystemS3;
if (c.SystemS4) ret |= PowerCapabilities.SystemS4;
if (c.SystemS5) ret |= PowerCapabilities.SystemS5;
if (c.HiberFilePresent) ret |= PowerCapabilities.HiberFilePresent;
if (c.FullWake) ret |= PowerCapabilities.FullWake;
if (c.VideoDimPresent) ret |= PowerCapabilities.VideoDimPresent;
if (c.ApmPresent) ret |= PowerCapabilities.ApmPresent;
if (c.UpsPresent) ret |= PowerCapabilities.UpsPresent;
if (c.ThermalControl) ret |= PowerCapabilities.ThermalControl;
if (c.ProcessorThrottle) ret |= PowerCapabilities.ProcessorThrottle;
if (c.FastSystemS4) ret |= PowerCapabilities.FastSystemS4;
if (c.Hiberboot) ret |= PowerCapabilities.Hiberboot;
if (c.WakeAlarmPresent) ret |= PowerCapabilities.WakeAlarmPresent;
if (c.AoAc) ret |= PowerCapabilities.AoAc;
if (c.DiskSpinDown) ret |= PowerCapabilities.DiskSpinDown;
if (c.AoAcConnectivitySupported) ret |= PowerCapabilities.AoAcConnectivitySupported;
if (c.SystemBatteriesPresent) ret |= PowerCapabilities.SystemBatteriesPresent;
if (c.BatteriesAreShortTerm) ret |= PowerCapabilities.BatteriesAreShortTerm;
return ret;
}
}
/// <summary>Gets the device's battery saver status, indicating when to save energy.</summary>
/// <value>Returns a <see cref="EnergySaverStatus"/> value.</value>
public static EnergySaverStatus EnergySaverStatus
{
get
{
var s = GetStatus();
return s.ACLineStatus == AC_STATUS.AC_ONLINE || s.BatteryFlag == BATTERY_STATUS.BATTERY_NONE ? EnergySaverStatus.Disabled : (s.SystemStatusFlag == 0 ? EnergySaverStatus.Off : EnergySaverStatus.On);
}
}
/// <summary>Gets a value indicating whether the system is on AC power (plugged in).</summary>
/// <value><see langword="true"/> if on AC power; otherwise, <see langword="false"/>.</value>
public static bool OnACPower => GetStatus().ACLineStatus == AC_STATUS.AC_ONLINE;
/// <summary>Indicates the OEM's preferred power management profile for this device.</summary>
public static POWER_PLATFORM_ROLE PlatformRole => PInvokeClient.Windows8.IsPlatformSupported() ? PowerDeterminePlatformRoleEx(PowerPlatformRoleVersion.POWER_PLATFORM_ROLE_V2) : PowerDeterminePlatformRole();
/// <summary>A collection of the powered devices on the system. Filters on this list can be set as properties.</summary>
/// <value>Returns a <see cref="PoweredDeviceCollection"/> value.</value>
public static PoweredDeviceCollection PoweredDevices { get; } = new PoweredDeviceCollection();
/// <summary>Gets the device's power supply status.</summary>
/// <value>Returns a <see cref="PowerSupplyStatus"/> value.</value>
public static PowerSupplyStatus PowerSupplyStatus => GetStatus().ACLineStatus switch
{
AC_STATUS.AC_ONLINE => PowerSupplyStatus.Adequate,
AC_STATUS.AC_LINE_BACKUP_POWER => PowerSupplyStatus.Inadequate,
_ => PowerSupplyStatus.NotPresent,
};
/// <summary>Gets the total percentage of charge remaining from all batteries connected to the device.</summary>
/// <value>Returns a <c>int?</c> value from 0 to 100, or <see langword="null"/> if the status is unknown.</value>
public static int? RemainingChargePercent { get { var p = GetStatus().BatteryLifePercent; return p == 255 ? (int?)null : p; } }
/// <summary>Gets the total runtime remaining from all batteries connected to the device.</summary>
/// <value>
/// The total runtime remaining from all batteries connected to the device, or <see langword="null"/> if the status is unknown or
/// connected to AC power.
/// </value>
public static TimeSpan? RemainingDischargeTime { get { var s = GetStatus().BatteryLifeTime; return s == uint.MaxValue ? (TimeSpan?)null : TimeSpan.FromSeconds(s); } }
/// <summary>Gets the collection of all power schemes on this device.</summary>
/// <value>Returns a <see cref="PowerSchemeCollection"/> value.</value>
public static PowerSchemeCollection Schemes { get; } = new PowerSchemeCollection();
internal static string NameForGuid(Guid guid) => typeof(PowrProf).GetFields(BindingFlags.Public | BindingFlags.Static).FirstOrDefault(i => i.FieldType == typeof(Guid) && guid.Equals(i.GetValue(null)))?.Name;
private static SYSTEM_POWER_CAPABILITIES GetCapabilities() => GetPwrCapabilities(out var c) ? c : default;
private static SYSTEM_POWER_STATUS GetStatus() => GetSystemPowerStatus(out var s) ? s : default;
}
/// <summary>Represents a device on the system that has power requirements.</summary>
public class PoweredDevice
{
private readonly bool hw;
internal PoweredDevice(string id, bool isHW)
{
Id = id;
hw = isHW;
}
/// <summary>Gets or sets the identifier for the device.</summary>
/// <value>The identifier.</value>
public string Id { get; protected set; }
/// <summary>Gets or sets a value indicating whether the device is wake enabled.</summary>
/// <value><see langword="true"/> if wake enabled; otherwise, <see langword="false"/>.</value>
public bool WakeEnabled
{
get => PoweredDeviceCollection.GetEnumValues((hw ? PDQUERY.DEVICEPOWER_HARDWAREID : 0) | PDQUERY.DEVICEPOWER_FILTER_WAKEENABLED).Any(s => s == Id);
set => DevicePowerSetDeviceState(Id, value ? PDSET.DEVICEPOWER_SET_WAKEENABLED : PDSET.DEVICEPOWER_CLEAR_WAKEENABLED);
}
/// <inheritdoc/>
public override string ToString() => Id;
}
/// <summary>Retrieves the list, optionally filtered, of the powered devices on the system.</summary>
/// <seealso cref="VirtualDictionary{TKey, TValue}"/>
public class PoweredDeviceCollection : VirtualDictionary<string, PoweredDevice>
{
private static Finalizer finalizer;
internal PoweredDeviceCollection() : base(true)
{
}
/// <inheritdoc/>
public override ICollection<string> Keys => GetEnumValues(PDQUERY).ToList();
/// <summary>Gets or sets a value indicating whether to display only devices that are currently present in the system.</summary>
/// <value><see langword="true"/> to retrieve only present devices; otherwise, <see langword="false"/>.</value>
public bool OnlyPresentDevices { get; set; }
/// <summary>Gets or sets a value indicating whether to display only devices that are wake-enabled.</summary>
/// <value><see langword="true"/> if to retrieve only wake enabled devices; otherwise, <see langword="false"/>.</value>
public bool OnlyWakeEnabledDevices { get; set; }
/// <summary>Gets or sets a value indicating whether to display the hardware identifier rather than a friendly name.</summary>
/// <value>
/// <see langword="true"/> to display the hardware identifier; otherwise, <see langword="false"/> to display the friendly name.
/// </value>
public bool UseHardwareId { get; set; }
/// <inheritdoc/>
public override ICollection<PoweredDevice> Values => GetEnumValues(PDQUERY).Select(s => new PoweredDevice(s, UseHardwareId)).ToList();
/// <inheritdoc/>
protected override IEnumerable<KeyValuePair<string, PoweredDevice>> Items => GetEnumValues(PDQUERY).Select(s => new KeyValuePair<string, PoweredDevice>(s, new PoweredDevice(s, UseHardwareId)));
private PDQUERY PDQUERY => (UseHardwareId ? PDQUERY.DEVICEPOWER_HARDWAREID : 0) | (OnlyPresentDevices ? PDQUERY.DEVICEPOWER_FILTER_DEVICES_PRESENT : 0) | (OnlyWakeEnabledDevices ? PDQUERY.DEVICEPOWER_FILTER_WAKEENABLED : 0);
/// <inheritdoc/>
public override bool TryGetValue(string key, out PoweredDevice value)
{
var ret = GetEnumValues(UseHardwareId ? PDQUERY.DEVICEPOWER_HARDWAREID : 0).Contains(key);
value = ret ? new PoweredDevice(key, UseHardwareId) : null;
return ret;
}
internal static IEnumerable<string> GetEnumValues(PDQUERY filter = 0, PDCAP flags = 0)
{
const uint bufSz = 1024;
ValidateOpened();
var sz = bufSz;
var sb = new StringBuilder((int)sz / 2, (int)sz / 2);
for (var i = 0U; ; i++)
{
sb.Clear();
if (DevicePowerEnumDevices(i, filter, flags, sb, ref sz))
yield return sb.ToString();
else
break;
}
}
private static void ValidateOpened()
{
if (finalizer is null) finalizer = new Finalizer();
}
private class Finalizer
{
internal Finalizer() => DevicePowerOpen();
~Finalizer() => DevicePowerClose();
}
}
/// <summary>Represents a system power scheme (power plan).</summary>
public class PowerScheme : IEquatable<Guid>, IEquatable<PowerScheme>
{
/// <summary>The well-known, system defined Balance (or Typical) power scheme with fairly aggressive power savings measures.</summary>
public static readonly PowerScheme Balanced = new PowerScheme(GUID_TYPICAL_POWER_SAVINGS);
/// <summary>The well-known, system defined High Performance (or Minimum) power scheme with almost no power savings measures.</summary>
public static readonly PowerScheme HighPerformance = new PowerScheme(GUID_MIN_POWER_SAVINGS);
/// <summary>
/// The well-known, system defined Power Saver (or Max) power scheme with very aggressive power savings measures to help stretch
/// battery life.
/// </summary>
public static readonly PowerScheme PowerSaver = new PowerScheme(GUID_MAX_POWER_SAVINGS);
internal PowerScheme(Guid g)
{
Guid = g;
Groups = new PowerSchemeGroupCollection(g);
}
/// <summary>Gets the active power scheme for the system.</summary>
/// <value>Returns a <see cref="PowerScheme"/> value for the active scheme.</value>
public static PowerScheme Active => PowerGetActiveScheme(out var g).Succeeded ? new PowerScheme(g) : throw new SystemException();
/// <summary>Gets the variable name of the GUID defined in the Windows SDK for this scheme.</summary>
/// <value>The API based variable name.</value>
public string ApiName => PowerManager.NameForGuid(Guid);
/// <summary>Gets or sets the description of the scheme.</summary>
/// <value>The description.</value>
public string Description
{
get => PowerReadDescription(Guid);
set => PowerWriteDescription(Guid, null, null, value).ThrowIfFailed();
}
/// <summary>Gets the subgroups defined for this scheme.</summary>
/// <value>Returns a <see cref="PowerSchemeGroupCollection"/> value.</value>
public PowerSchemeGroupCollection Groups { get; }
/// <summary>Gets or sets a value indicating whether this scheme is the active scheme for the system.</summary>
/// <value><see langword="true"/> if this instance is active; otherwise, <see langword="false"/>.</value>
public bool IsActive
{
get => PowerGetActiveScheme(out var g).Succeeded && Guid.Equals(g);
set => PowerSetActiveScheme(default, Guid).ThrowIfFailed();
}
/// <summary>Gets or sets the friendly name of the scheme.</summary>
/// <value>The friendly name.</value>
public string Name
{
get => PowerReadFriendlyName(Guid);
set => PowerWriteFriendlyName(Guid, null, null, value).ThrowIfFailed();
}
/// <summary>Gets the underlying GUID for the scheme.</summary>
/// <value>Returns a <see cref="Guid"/> value.</value>
protected internal Guid Guid { get; }
/// <summary>Returns a duplicates this scheme that can be edited and set as the new active scheme.</summary>
/// <returns>An editable duplicate of the current scheme.</returns>
public PowerScheme Duplicate()
{
PowerDuplicateScheme(default, Guid, out var h).ThrowIfFailed();
return new PowerScheme(h.ToStructure<Guid>());
}
/// <summary>Determines whether the specified <see cref="Guid"/>, is equal to this instance.</summary>
/// <param name="other">The <see cref="Guid"/> to compare with this instance.</param>
/// <returns><see langword="true"/> if the specified <see cref="Guid"/> is equal to this instance; otherwise, <see langword="false"/>.</returns>
public bool Equals(Guid other) => Guid.Equals(other);
/// <summary>Determines whether the specified <see cref="PowerScheme"/>, is equal to this instance.</summary>
/// <param name="other">The <see cref="PowerScheme"/> to compare with this instance.</param>
/// <returns><see langword="true"/> if the specified <see cref="PowerScheme"/> is equal to this instance; otherwise, <see langword="false"/>.</returns>
public bool Equals(PowerScheme other) => !(other is null) && Equals(other.Guid);
/// <summary>Determines whether the specified <see cref="object"/>, is equal to this instance.</summary>
/// <param name="obj">The <see cref="object"/> to compare with this instance.</param>
/// <returns><see langword="true"/> if the specified <see cref="object"/> is equal to this instance; otherwise, <see langword="false"/>.</returns>
public override bool Equals(object obj) => obj is Guid g ? Equals(g) : obj is PowerScheme s && Equals(s);
/// <summary>Returns a hash code for this instance.</summary>
/// <returns>A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table.</returns>
public override int GetHashCode() => Guid.GetHashCode();
//public System.Drawing.Icon Icon { get; set; }
}
/// <summary>Represents a collection of all the power schemes available on the system.</summary>
/// <seealso cref="VirtualDictionary{Guid, PowerScheme}"/>
public class PowerSchemeCollection : VirtualDictionary<Guid, PowerScheme>
{
internal PowerSchemeCollection() : base(!CanUserWritePwrScheme())
{
}
/// <inheritdoc/>
public override ICollection<Guid> Keys => PowerEnumerate<Guid>(null, null).ToList();
/// <summary>Imports a power scheme from a file.</summary>
/// <param name="importFilePath">The path to a power scheme backup file created by <c>PowerCfg.Exe /Export</c>.</param>
/// <returns>A <see cref="PowerScheme"/> derived from the file.</returns>
public static PowerScheme ImportFromFile(string importFilePath)
{
PowerImportPowerScheme(default, importFilePath, out var memG).ThrowIfFailed();
return new PowerScheme(memG.ToStructure<Guid>());
}
/// <summary>
/// Replaces the default power schemes with the current user's power schemes. This allows an administrator to change the default
/// power schemes for the system. Replacing the default schemes enables users to use the <c>Restore Defaults</c> option in the
/// Control Panel <c>Power Options</c> application to restore customized power scheme defaults instead of the original Windows power
/// scheme defaults.
/// </summary>
/// <remarks>The caller must be a member of the local Administrators group.</remarks>
public static void ReplaceDefaultPowerSchemes() => PowerReplaceDefaultPowerSchemes().ThrowIfFailed();
/// <summary>
/// Replaces the power schemes for the system with default power schemes. All current power schemes and settings are deleted and
/// replaced with the default system power schemes.
/// </summary>
/// <remarks>The caller must be a member of the local Administrators group.</remarks>
public static void RestoreDefaultPowerSchemes() => PowerRestoreDefaultPowerSchemes().ThrowIfFailed();
/// <inheritdoc/>
public override bool Remove(Guid key) => PowerDeleteScheme(default, key).Succeeded;
/// <inheritdoc/>
public override bool TryGetValue(Guid key, out PowerScheme value)
{
value = new PowerScheme(key); return true;
}
// public static POWER_POLICY ActivePowerPolicy => GetCurrentPowerPolicies(out var _, out var p) ? p : default; public static
// GLOBAL_POWER_POLICY GlobalPowerPolicy => GetCurrentPowerPolicies(out var p, out var _) ? p : default;
}
/// <summary>Represents a subgroup of a system power scheme (power plan).</summary>
public class PowerSchemeGroup
{
/// <summary>The scheme's guid.</summary>
protected Guid scheme;
/// <summary>The scheme's subgroup's guid.</summary>
protected Guid subgroup;
internal PowerSchemeGroup(Guid scheme, Guid group)
{
this.scheme = scheme;
subgroup = group;
Settings = new PowerSchemeSettingCollection(scheme, subgroup);
}
/// <summary>Gets the variable name of the GUID defined in the Windows SDK for this subgroup.</summary>
/// <value>The API based variable name.</value>
public string ApiName => PowerManager.NameForGuid(subgroup);
/// <summary>Gets or sets the description of the subgroup.</summary>
/// <value>The description.</value>
public string Description
{
get => PowerReadDescription(scheme, subgroup);
set => PowerWriteDescription(scheme, subgroup, null, value).ThrowIfFailed();
}
/// <summary>Gets or sets the friendly name of the subgroup.</summary>
/// <value>The friendly name.</value>
public string Name
{
get => PowerReadFriendlyName(scheme, subgroup);
set => PowerWriteFriendlyName(scheme, subgroup, null, value).ThrowIfFailed();
}
/// <summary>Gets the settings defined for this subgroup.</summary>
/// <value>Returns a <see cref="PowerSchemeSettingCollection"/> value.</value>
public PowerSchemeSettingCollection Settings { get; }
}
/// <summary>Represents a collection of all the subgroups available under a power scheme on the system.</summary>
public class PowerSchemeGroupCollection : VirtualDictionary<Guid, PowerSchemeGroup>
{
/// <summary>The scheme's guid.</summary>
protected Guid scheme;
internal PowerSchemeGroupCollection(Guid scheme) : base(false) => this.scheme = scheme;
/// <inheritdoc/>
public override ICollection<Guid> Keys => PowerEnumerate<Guid>(scheme, null).Concat(new[] { NO_SUBGROUP_GUID }).ToList();
/// <inheritdoc/>
public override bool TryGetValue(Guid key, out PowerSchemeGroup value)
{
value = new PowerSchemeGroup(scheme, key); return true;
}
}
/// <summary>Represents a setting on a subgroup.</summary>
public class PowerSchemeSetting
{
/// <summary>The scheme's guid.</summary>
protected Guid scheme;
/// <summary>The scheme's setting guid.</summary>
protected Guid setting;
/// <summary>The scheme's subgroup guid.</summary>
protected Guid subgroup;
internal PowerSchemeSetting(Guid scheme, Guid group, Guid setting)
{
this.scheme = scheme;
subgroup = group;
this.setting = setting;
}
private delegate Win32Error IdxWriter(HKEY rootSystemPowerKey, in Guid schemePersonalityGuid, in Guid subGroupOfPowerSettingsGuid, in Guid powerSettingGuid, uint index);
/// <summary>Retrieves the AC power value for the specified power setting.</summary>
/// <value>Returns the data value.</value>
public object ACValue
{
get
{
var sz = 0U;
PowerReadACValue(default, scheme, subgroup, setting, out _, IntPtr.Zero, ref sz).ThrowIfFailed();
using var mem = new SafeHGlobalHandle((int)sz);
REG_VALUE_TYPE regType;
PowerReadACValue(default, scheme, subgroup, setting, out regType, mem, ref sz).ThrowIfFailed();
return regType.GetValue(mem, sz);
}
}
/// <summary>Gets or sets the default AC index of the specified power setting.</summary>
/// <value>The default AC index.</value>
public int ACValueDefaultIndex
{
get => PowerReadACDefaultIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1;
set => WriteIndex(PowerWriteACDefaultIndex, value);
}
/// <summary>Gets or sets the AC index of the specified power setting.</summary>
/// <value>The AC index.</value>
public int ACValueIndex
{
get => PowerReadACValueIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1;
set => WriteIndex(PowerWriteACValueIndex, value);
}
/// <summary>Gets the variable name of the GUID defined in the Windows SDK for this setting.</summary>
/// <value>The API based variable name.</value>
public string ApiName => PowerManager.NameForGuid(setting);
/// <summary>Retrieves the DC power value for the specified power setting.</summary>
/// <value>Returns the data value.</value>
public object DCValue
{
get
{
var sz = 0U;
PowerReadDCValue(default, scheme, subgroup, setting, out _, IntPtr.Zero, ref sz).ThrowIfFailed();
using var mem = new SafeHGlobalHandle((int)sz);
REG_VALUE_TYPE regType;
PowerReadDCValue(default, scheme, subgroup, setting, out regType, mem, ref sz).ThrowIfFailed();
return regType.GetValue(mem, sz);
}
}
/// <summary>Gets or sets the default DC index of the specified power setting.</summary>
/// <value>The default DC index.</value>
public int DCValueDefaultIndex
{
get => PowerReadDCDefaultIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1;
set => WriteIndex(PowerWriteDCDefaultIndex, value);
}
/// <summary>Gets or sets the DC index of the specified power setting.</summary>
/// <value>The DC index.</value>
public int DCValueIndex
{
get => PowerReadDCValueIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1;
set => WriteIndex(PowerWriteDCValueIndex, value);
}
/// <summary>Gets or sets the description of the setting.</summary>
/// <value>The description.</value>
public string Description
{
get => PowerReadDescription(scheme, subgroup, setting);
set { PowerWriteDescription(scheme, subgroup, setting, value).ThrowIfFailed(); PowerSetActiveScheme(default, scheme).ThrowIfFailed(); }
}
/// <summary>Gets a value indicating whether a range is defined.</summary>
/// <value><see langword="true"/> if a range is defined; otherwise, <see langword="false"/>.</value>
public bool IsRange => PowerIsSettingRangeDefined(subgroup, setting);
/// <summary>Gets or sets the friendly name of the setting.</summary>
/// <value>The friendly name.</value>
public string Name
{
get => PowerReadFriendlyName(scheme, subgroup, setting);
set { PowerWriteFriendlyName(scheme, subgroup, setting, value).ThrowIfFailed(); PowerSetActiveScheme(default, scheme).ThrowIfFailed(); }
}
/// <summary>Gets the possible values for this setting.</summary>
/// <value>Returns a <see cref="IEnumerable{T}"/> value.</value>
public IEnumerable<(object value, string name, string description)> PossibleValues
{
get
{
if (IsRange) yield break;
for (var i = 0U; ; i++)
{
var err = FunctionHelper.CallMethodWithStrBuf((StringBuilder sb, ref uint ssz) => PowerReadPossibleFriendlyName(default, subgroup, setting, i, sb, ref ssz), out var name, (ssz, r) => ssz > 0);
if (err.Failed)
break;
err = FunctionHelper.CallMethodWithStrBuf((StringBuilder sb, ref uint ssz) => PowerReadPossibleDescription(default, subgroup, setting, i, sb, ref ssz), out var desc, (ssz, r) => ssz > 0);
if (err.Failed)
break;
var sz = 0U;
object obj = null;
err = PowerReadPossibleValue(default, subgroup, setting, out var regType, i, IntPtr.Zero, ref sz);
if (err.Succeeded)
{
using var mem = new SafeHGlobalHandle((int)sz);
err = PowerReadPossibleValue(default, subgroup, setting, out regType, i, mem, ref sz);
if (err.Failed)
break;
obj = regType.GetValue(mem, sz);
}
yield return (obj, name, desc);
}
}
}
/// <summary>Gets or sets the range information for this setting.</summary>
/// <value>The range detail (min/max value, increment and unit specifier.</value>
/// <exception cref="InvalidOperationException">Setting is not a range value.</exception>
public (uint min, uint max, uint increment, string unitsSpecifier) Range
{
get
{
try
{
if (IsRange)
{
PowerReadValueMin(default, subgroup, setting, out var min).ThrowIfFailed();
PowerReadValueMax(default, subgroup, setting, out var max).ThrowIfFailed();
PowerReadValueIncrement(default, subgroup, setting, out var incr).ThrowIfFailed();
FunctionHelper.CallMethodWithStrBuf((StringBuilder sb, ref uint sz) => PowerReadValueUnitsSpecifier(default, subgroup, setting, sb, ref sz), out var spec, (sz, r) => sz > 0).ThrowIfFailed();
return (min, max, incr, spec);
}
}
catch { }
return (0, 0, 0, null);
}
set
{
if (!IsRange) throw new InvalidOperationException("Setting is not a range value.");
PowerWriteValueMin(default, subgroup, setting, value.min).ThrowIfFailed();
PowerWriteValueMax(default, subgroup, setting, value.max).ThrowIfFailed();
PowerWriteValueIncrement(default, subgroup, setting, value.increment).ThrowIfFailed();
PowerWriteValueUnitsSpecifier(default, subgroup, setting, value.unitsSpecifier, (uint)((value.unitsSpecifier?.Length + 1) * 2 ?? 0)).ThrowIfFailed();
PowerSetActiveScheme(default, scheme).ThrowIfFailed();
}
}
private void WriteIndex(IdxWriter func, int value)
{
func(default, scheme, subgroup, setting, unchecked((uint)value)).ThrowIfFailed();
PowerSetActiveScheme(default, scheme).ThrowIfFailed();
}
}
/// <summary>Represents a collection of all settings for a subgroup and power scheme on the system.</summary>
public class PowerSchemeSettingCollection : VirtualDictionary<Guid, PowerSchemeSetting>
{
/// <summary>The scheme's guid.</summary>
protected Guid scheme;
/// <summary>The scheme's subgroup guid.</summary>
protected Guid subgroup;
internal PowerSchemeSettingCollection(Guid scheme, Guid subgroup) : base(false)
{
this.scheme = scheme; this.subgroup = subgroup;
}
/// <inheritdoc/>
public override ICollection<Guid> Keys => PowerEnumerate<Guid>(scheme, subgroup).ToList();
/// <inheritdoc/>
public override bool TryGetValue(Guid key, out PowerSchemeSetting value)
{
value = new PowerSchemeSetting(scheme, subgroup, key); return true;
}
}
}