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 { /// Indicates the status of the battery. public enum BatteryStatus { /// The battery or battery controller is not present. NotPresent, /// The battery is discharging. Discharging, /// The battery is idle. Idle, /// The battery is charging. Charging } /// Specifies the status of battery saver. public enum EnergySaverStatus { /// Battery saver is off permanently or the device is plugged in. Disabled, /// Battery saver is off now, but ready to turn on automatically. Off, /// Battery saver is on. Save energy where possible. On } /// Specifies the power capabilities of a device. [Flags] public enum PowerCapabilities { /// There is a system power button. PowerButtonPresent = 1 << 0, /// There is a system sleep button. SleepButtonPresent = 1 << 1, /// There is a lid switch. LidPresent = 1 << 2, /// The operating system supports sleep state S1. SystemS1 = 1 << 3, /// The operating system supports sleep state S2. SystemS2 = 1 << 4, /// The operating system supports sleep state S3. SystemS3 = 1 << 5, /// The operating system supports sleep state S4 (hibernation). SystemS4 = 1 << 6, /// The operating system supports power off state S5 (soft off). SystemS5 = 1 << 7, /// The system hibernation file is present. HiberFilePresent = 1 << 8, /// The system supports wake capabilities. FullWake = 1 << 9, /// The system supports video display dimming capabilities. VideoDimPresent = 1 << 10, /// The system supports APM BIOS power management features. ApmPresent = 1 << 11, /// There is an uninterruptible power supply (UPS). UpsPresent = 1 << 12, /// The system supports thermal zones. ThermalControl = 1 << 13, /// The system supports processor throttling. ProcessorThrottle = 1 << 14, /// The system supports the hybrid sleep state. FastSystemS4 = 1 << 15, /// /// 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. /// Hiberboot = 1 << 16, /// /// The platform has support for ACPI wake alarm devices. For more details on wake alarm devices, please see the ACPI specification /// section 9.18. /// WakeAlarmPresent = 1 << 17, /// The system supports the S0 low power idle model. AoAc = 1 << 18, /// The system supports allowing the removal of power to fixed disk devices. DiskSpinDown = 1 << 19, /// AoAcConnectivitySupported = 1 << 20, /// There are one or more batteries in the system. SystemBatteriesPresent = 1 << 21, /// The system batteries are short-term. Short-term batteries are used in uninterruptible power supplies (UPS). BatteriesAreShortTerm = 1 << 22 } /// Represents the device's power supply status. public enum PowerSupplyStatus { /// The device has no power supply. NotPresent, /// The device has an inadequate power supply. Inadequate, /// The device has an adequate power supply. Adequate } /// /// 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. /// 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; */ /// Gets the device's battery status. /// Returns a 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, }; /// Gets flags indicating the system's power capabilities. /// Returns a 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; } } /// Gets the device's battery saver status, indicating when to save energy. /// Returns a 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); } } /// Gets a value indicating whether the system is on AC power (plugged in). /// if on AC power; otherwise, . public static bool OnACPower => GetStatus().ACLineStatus == AC_STATUS.AC_ONLINE; /// Indicates the OEM's preferred power management profile for this device. public static POWER_PLATFORM_ROLE PlatformRole => PInvokeClient.Windows8.IsPlatformSupported() ? PowerDeterminePlatformRoleEx(PowerPlatformRoleVersion.POWER_PLATFORM_ROLE_V2) : PowerDeterminePlatformRole(); /// A collection of the powered devices on the system. Filters on this list can be set as properties. /// Returns a value. public static PoweredDeviceCollection PoweredDevices { get; } = new PoweredDeviceCollection(); /// Gets the device's power supply status. /// Returns a value. public static PowerSupplyStatus PowerSupplyStatus => GetStatus().ACLineStatus switch { AC_STATUS.AC_ONLINE => PowerSupplyStatus.Adequate, AC_STATUS.AC_LINE_BACKUP_POWER => PowerSupplyStatus.Inadequate, _ => PowerSupplyStatus.NotPresent, }; /// Gets the total percentage of charge remaining from all batteries connected to the device. /// Returns a int? value from 0 to 100, or if the status is unknown. public static int? RemainingChargePercent { get { var p = GetStatus().BatteryLifePercent; return p == 255 ? (int?)null : p; } } /// Gets the total runtime remaining from all batteries connected to the device. /// /// The total runtime remaining from all batteries connected to the device, or if the status is unknown or /// connected to AC power. /// public static TimeSpan? RemainingDischargeTime { get { var s = GetStatus().BatteryLifeTime; return s == uint.MaxValue ? (TimeSpan?)null : TimeSpan.FromSeconds(s); } } /// Gets the collection of all power schemes on this device. /// Returns a 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; } /// Represents a device on the system that has power requirements. public class PoweredDevice { private readonly bool hw; internal PoweredDevice(string id, bool isHW) { Id = id; hw = isHW; } /// Gets or sets the identifier for the device. /// The identifier. public string Id { get; protected set; } /// Gets or sets a value indicating whether the device is wake enabled. /// if wake enabled; otherwise, . 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); } /// public override string ToString() => Id; } /// Retrieves the list, optionally filtered, of the powered devices on the system. /// public class PoweredDeviceCollection : VirtualDictionary { private static Finalizer finalizer; internal PoweredDeviceCollection() : base(true) { } /// public override ICollection Keys => GetEnumValues(PDQUERY).ToList(); /// Gets or sets a value indicating whether to display only devices that are currently present in the system. /// to retrieve only present devices; otherwise, . public bool OnlyPresentDevices { get; set; } /// Gets or sets a value indicating whether to display only devices that are wake-enabled. /// if to retrieve only wake enabled devices; otherwise, . public bool OnlyWakeEnabledDevices { get; set; } /// Gets or sets a value indicating whether to display the hardware identifier rather than a friendly name. /// /// to display the hardware identifier; otherwise, to display the friendly name. /// public bool UseHardwareId { get; set; } /// public override ICollection Values => GetEnumValues(PDQUERY).Select(s => new PoweredDevice(s, UseHardwareId)).ToList(); /// protected override IEnumerable> Items => GetEnumValues(PDQUERY).Select(s => new KeyValuePair(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); /// 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 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(); } } /// Represents a system power scheme (power plan). public class PowerScheme : IEquatable, IEquatable { /// The well-known, system defined Balance (or Typical) power scheme with fairly aggressive power savings measures. public static readonly PowerScheme Balanced = new PowerScheme(GUID_TYPICAL_POWER_SAVINGS); /// The well-known, system defined High Performance (or Minimum) power scheme with almost no power savings measures. public static readonly PowerScheme HighPerformance = new PowerScheme(GUID_MIN_POWER_SAVINGS); /// /// The well-known, system defined Power Saver (or Max) power scheme with very aggressive power savings measures to help stretch /// battery life. /// public static readonly PowerScheme PowerSaver = new PowerScheme(GUID_MAX_POWER_SAVINGS); internal PowerScheme(Guid g) { Guid = g; Groups = new PowerSchemeGroupCollection(g); } /// Gets the active power scheme for the system. /// Returns a value for the active scheme. public static PowerScheme Active => PowerGetActiveScheme(out var g).Succeeded ? new PowerScheme(g) : throw new SystemException(); /// Gets the variable name of the GUID defined in the Windows SDK for this scheme. /// The API based variable name. public string ApiName => PowerManager.NameForGuid(Guid); /// Gets or sets the description of the scheme. /// The description. public string Description { get => PowerReadDescription(Guid); set => PowerWriteDescription(Guid, null, null, value).ThrowIfFailed(); } /// Gets the subgroups defined for this scheme. /// Returns a value. public PowerSchemeGroupCollection Groups { get; } /// Gets or sets a value indicating whether this scheme is the active scheme for the system. /// if this instance is active; otherwise, . public bool IsActive { get => PowerGetActiveScheme(out var g).Succeeded && Guid.Equals(g); set => PowerSetActiveScheme(default, Guid).ThrowIfFailed(); } /// Gets or sets the friendly name of the scheme. /// The friendly name. public string Name { get => PowerReadFriendlyName(Guid); set => PowerWriteFriendlyName(Guid, null, null, value).ThrowIfFailed(); } /// Gets the underlying GUID for the scheme. /// Returns a value. protected internal Guid Guid { get; } /// Returns a duplicates this scheme that can be edited and set as the new active scheme. /// An editable duplicate of the current scheme. public PowerScheme Duplicate() { PowerDuplicateScheme(default, Guid, out var h).ThrowIfFailed(); return new PowerScheme(h.ToStructure()); } /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// if the specified is equal to this instance; otherwise, . public bool Equals(Guid other) => Guid.Equals(other); /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// if the specified is equal to this instance; otherwise, . public bool Equals(PowerScheme other) => !(other is null) && Equals(other.Guid); /// Determines whether the specified , is equal to this instance. /// The to compare with this instance. /// if the specified is equal to this instance; otherwise, . public override bool Equals(object obj) => obj is Guid g ? Equals(g) : obj is PowerScheme s && Equals(s); /// Returns a hash code for this instance. /// A hash code for this instance, suitable for use in hashing algorithms and data structures like a hash table. public override int GetHashCode() => Guid.GetHashCode(); //public System.Drawing.Icon Icon { get; set; } } /// Represents a collection of all the power schemes available on the system. /// public class PowerSchemeCollection : VirtualDictionary { internal PowerSchemeCollection() : base(!CanUserWritePwrScheme()) { } /// public override ICollection Keys => PowerEnumerate(null, null).ToList(); /// Imports a power scheme from a file. /// The path to a power scheme backup file created by PowerCfg.Exe /Export. /// A derived from the file. public static PowerScheme ImportFromFile(string importFilePath) { PowerImportPowerScheme(default, importFilePath, out var memG).ThrowIfFailed(); return new PowerScheme(memG.ToStructure()); } /// /// 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 Restore Defaults option in the /// Control Panel Power Options application to restore customized power scheme defaults instead of the original Windows power /// scheme defaults. /// /// The caller must be a member of the local Administrators group. public static void ReplaceDefaultPowerSchemes() => PowerReplaceDefaultPowerSchemes().ThrowIfFailed(); /// /// 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. /// /// The caller must be a member of the local Administrators group. public static void RestoreDefaultPowerSchemes() => PowerRestoreDefaultPowerSchemes().ThrowIfFailed(); /// public override bool Remove(Guid key) => PowerDeleteScheme(default, key).Succeeded; /// 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; } /// Represents a subgroup of a system power scheme (power plan). public class PowerSchemeGroup { /// The scheme's guid. protected Guid scheme; /// The scheme's subgroup's guid. protected Guid subgroup; internal PowerSchemeGroup(Guid scheme, Guid group) { this.scheme = scheme; subgroup = group; Settings = new PowerSchemeSettingCollection(scheme, subgroup); } /// Gets the variable name of the GUID defined in the Windows SDK for this subgroup. /// The API based variable name. public string ApiName => PowerManager.NameForGuid(subgroup); /// Gets or sets the description of the subgroup. /// The description. public string Description { get => PowerReadDescription(scheme, subgroup); set => PowerWriteDescription(scheme, subgroup, null, value).ThrowIfFailed(); } /// Gets or sets the friendly name of the subgroup. /// The friendly name. public string Name { get => PowerReadFriendlyName(scheme, subgroup); set => PowerWriteFriendlyName(scheme, subgroup, null, value).ThrowIfFailed(); } /// Gets the settings defined for this subgroup. /// Returns a value. public PowerSchemeSettingCollection Settings { get; } } /// Represents a collection of all the subgroups available under a power scheme on the system. public class PowerSchemeGroupCollection : VirtualDictionary { /// The scheme's guid. protected Guid scheme; internal PowerSchemeGroupCollection(Guid scheme) : base(false) => this.scheme = scheme; /// public override ICollection Keys => PowerEnumerate(scheme, null).Concat(new[] { NO_SUBGROUP_GUID }).ToList(); /// public override bool TryGetValue(Guid key, out PowerSchemeGroup value) { value = new PowerSchemeGroup(scheme, key); return true; } } /// Represents a setting on a subgroup. public class PowerSchemeSetting { /// The scheme's guid. protected Guid scheme; /// The scheme's setting guid. protected Guid setting; /// The scheme's subgroup guid. 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); /// Retrieves the AC power value for the specified power setting. /// Returns the data 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); } } /// Gets or sets the default AC index of the specified power setting. /// The default AC index. public int ACValueDefaultIndex { get => PowerReadACDefaultIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1; set => WriteIndex(PowerWriteACDefaultIndex, value); } /// Gets or sets the AC index of the specified power setting. /// The AC index. public int ACValueIndex { get => PowerReadACValueIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1; set => WriteIndex(PowerWriteACValueIndex, value); } /// Gets the variable name of the GUID defined in the Windows SDK for this setting. /// The API based variable name. public string ApiName => PowerManager.NameForGuid(setting); /// Retrieves the DC power value for the specified power setting. /// Returns the data 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); } } /// Gets or sets the default DC index of the specified power setting. /// The default DC index. public int DCValueDefaultIndex { get => PowerReadDCDefaultIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1; set => WriteIndex(PowerWriteDCDefaultIndex, value); } /// Gets or sets the DC index of the specified power setting. /// The DC index. public int DCValueIndex { get => PowerReadDCValueIndex(default, scheme, subgroup, setting, out var i).Succeeded ? (int)i : -1; set => WriteIndex(PowerWriteDCValueIndex, value); } /// Gets or sets the description of the setting. /// The description. public string Description { get => PowerReadDescription(scheme, subgroup, setting); set { PowerWriteDescription(scheme, subgroup, setting, value).ThrowIfFailed(); PowerSetActiveScheme(default, scheme).ThrowIfFailed(); } } /// Gets a value indicating whether a range is defined. /// if a range is defined; otherwise, . public bool IsRange => PowerIsSettingRangeDefined(subgroup, setting); /// Gets or sets the friendly name of the setting. /// The friendly name. public string Name { get => PowerReadFriendlyName(scheme, subgroup, setting); set { PowerWriteFriendlyName(scheme, subgroup, setting, value).ThrowIfFailed(); PowerSetActiveScheme(default, scheme).ThrowIfFailed(); } } /// Gets the possible values for this setting. /// Returns a 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); } } } /// Gets or sets the range information for this setting. /// The range detail (min/max value, increment and unit specifier. /// Setting is not a range value. 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(); } } /// Represents a collection of all settings for a subgroup and power scheme on the system. public class PowerSchemeSettingCollection : VirtualDictionary { /// The scheme's guid. protected Guid scheme; /// The scheme's subgroup guid. protected Guid subgroup; internal PowerSchemeSettingCollection(Guid scheme, Guid subgroup) : base(false) { this.scheme = scheme; this.subgroup = subgroup; } /// public override ICollection Keys => PowerEnumerate(scheme, subgroup).ToList(); /// public override bool TryGetValue(Guid key, out PowerSchemeSetting value) { value = new PowerSchemeSetting(scheme, subgroup, key); return true; } } }