Add support for battery monitoring (#612)

Thanks to @EMN-CSharp.
This commit is contained in:
EMN-CSharp
2022-02-07 17:05:36 +01:00
committed by GitHub
parent 0ed564e7c6
commit 5152b435fc
19 changed files with 844 additions and 149 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 648 B

@@ -57,6 +57,9 @@ namespace LibreHardwareMonitor.UI
case HardwareType.Psu:
image = Utilities.EmbeddedResources.GetImage("power-supply.png");
break;
case HardwareType.Battery:
image = Utilities.EmbeddedResources.GetImage("battery.png");
break;
default:
image = new Bitmap(1, 1);
break;
+32 -22
View File
@@ -1,7 +1,7 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// Partial Copyright (C) Michael Möller <mmoeller@openhardwaremonitor.org> and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.UI
@@ -59,6 +59,7 @@ namespace LibreHardwareMonitor.UI
this.fanControllerMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.hddMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.nicMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.psuMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.menuItem6 = new System.Windows.Forms.ToolStripSeparator();
this.exitMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.viewMenuItem = new System.Windows.Forms.ToolStripMenuItem();
@@ -125,6 +126,7 @@ namespace LibreHardwareMonitor.UI
this.timer = new System.Windows.Forms.Timer(this.components);
this.splitContainer = new LibreHardwareMonitor.UI.SplitContainerAdv();
this.treeView = new Aga.Controls.Tree.TreeViewAdv();
this.batteryMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.psuMenuItem = new System.Windows.Forms.ToolStripMenuItem();
this.backgroundUpdater = new System.ComponentModel.BackgroundWorker();
this.mainMenu.SuspendLayout();
@@ -240,19 +242,19 @@ namespace LibreHardwareMonitor.UI
// saveReportMenuItem
//
this.saveReportMenuItem.Name = "saveReportMenuItem";
this.saveReportMenuItem.Size = new System.Drawing.Size(145, 22);
this.saveReportMenuItem.Size = new System.Drawing.Size(180, 22);
this.saveReportMenuItem.Text = "Save Report...";
this.saveReportMenuItem.Click += new System.EventHandler(this.SaveReportMenuItem_Click);
//
// MenuItem2
//
this.MenuItem2.Name = "MenuItem2";
this.MenuItem2.Size = new System.Drawing.Size(142, 6);
this.MenuItem2.Size = new System.Drawing.Size(177, 6);
//
// resetMenuItem
//
this.resetMenuItem.Name = "resetMenuItem";
this.resetMenuItem.Size = new System.Drawing.Size(145, 22);
this.resetMenuItem.Size = new System.Drawing.Size(180, 22);
this.resetMenuItem.Text = "Reset";
this.resetMenuItem.Click += new System.EventHandler(this.ResetClick);
//
@@ -266,62 +268,69 @@ namespace LibreHardwareMonitor.UI
this.fanControllerMenuItem,
this.hddMenuItem,
this.nicMenuItem,
this.psuMenuItem});
this.psuMenuItem,
this.batteryMenuItem});
this.menuItem5.Name = "menuItem5";
this.menuItem5.Size = new System.Drawing.Size(145, 22);
this.menuItem5.Size = new System.Drawing.Size(180, 22);
this.menuItem5.Text = "Hardware";
//
// mainboardMenuItem
//
this.mainboardMenuItem.Name = "mainboardMenuItem";
this.mainboardMenuItem.Size = new System.Drawing.Size(160, 22);
this.mainboardMenuItem.Size = new System.Drawing.Size(180, 22);
this.mainboardMenuItem.Text = "Motherboard";
//
// cpuMenuItem
//
this.cpuMenuItem.Name = "cpuMenuItem";
this.cpuMenuItem.Size = new System.Drawing.Size(160, 22);
this.cpuMenuItem.Size = new System.Drawing.Size(180, 22);
this.cpuMenuItem.Text = "CPU";
//
// ramMenuItem
//
this.ramMenuItem.Name = "ramMenuItem";
this.ramMenuItem.Size = new System.Drawing.Size(160, 22);
this.ramMenuItem.Size = new System.Drawing.Size(180, 22);
this.ramMenuItem.Text = "RAM";
//
// gpuMenuItem
//
this.gpuMenuItem.Name = "gpuMenuItem";
this.gpuMenuItem.Size = new System.Drawing.Size(160, 22);
this.gpuMenuItem.Size = new System.Drawing.Size(180, 22);
this.gpuMenuItem.Text = "GPU";
//
// fanControllerMenuItem
//
this.fanControllerMenuItem.Name = "fanControllerMenuItem";
this.fanControllerMenuItem.Size = new System.Drawing.Size(160, 22);
this.fanControllerMenuItem.Size = new System.Drawing.Size(180, 22);
this.fanControllerMenuItem.Text = "Fan Controllers";
//
// hddMenuItem
//
this.hddMenuItem.Name = "hddMenuItem";
this.hddMenuItem.Size = new System.Drawing.Size(160, 22);
this.hddMenuItem.Size = new System.Drawing.Size(180, 22);
this.hddMenuItem.Text = "Hard Disk Drives";
//
// nicMenuItem
//
this.nicMenuItem.Name = "nicMenuItem";
this.nicMenuItem.Size = new System.Drawing.Size(160, 22);
this.nicMenuItem.Size = new System.Drawing.Size(180, 22);
this.nicMenuItem.Text = "Network";
//
// psuMenuItem
//
this.psuMenuItem.Name = "psuMenuItem";
this.psuMenuItem.Size = new System.Drawing.Size(180, 22);
this.psuMenuItem.Text = "Power supplies";
//
// menuItem6
//
this.menuItem6.Name = "menuItem6";
this.menuItem6.Size = new System.Drawing.Size(142, 6);
this.menuItem6.Size = new System.Drawing.Size(177, 6);
//
// exitMenuItem
//
this.exitMenuItem.Name = "exitMenuItem";
this.exitMenuItem.Size = new System.Drawing.Size(145, 22);
this.exitMenuItem.Size = new System.Drawing.Size(180, 22);
this.exitMenuItem.Text = "Exit";
this.exitMenuItem.Click += new System.EventHandler(this.ExitClick);
//
@@ -387,19 +396,19 @@ namespace LibreHardwareMonitor.UI
// valueMenuItem
//
this.valueMenuItem.Name = "valueMenuItem";
this.valueMenuItem.Size = new System.Drawing.Size(102, 22);
this.valueMenuItem.Size = new System.Drawing.Size(180, 22);
this.valueMenuItem.Text = "Value";
//
// minMenuItem
//
this.minMenuItem.Name = "minMenuItem";
this.minMenuItem.Size = new System.Drawing.Size(102, 22);
this.minMenuItem.Size = new System.Drawing.Size(180, 22);
this.minMenuItem.Text = "Min";
//
// maxMenuItem
//
this.maxMenuItem.Name = "maxMenuItem";
this.maxMenuItem.Size = new System.Drawing.Size(102, 22);
this.maxMenuItem.Size = new System.Drawing.Size(180, 22);
this.maxMenuItem.Text = "Max";
//
// optionsMenuItem
@@ -847,11 +856,11 @@ namespace LibreHardwareMonitor.UI
this.treeView.MouseMove += new System.Windows.Forms.MouseEventHandler(this.TreeView_MouseMove);
this.treeView.MouseUp += new System.Windows.Forms.MouseEventHandler(this.TreeView_MouseUp);
//
// psuMenuItem
// batteryMenuItem
//
this.psuMenuItem.Name = "psuMenuItem";
this.psuMenuItem.Size = new System.Drawing.Size(180, 22);
this.psuMenuItem.Text = "Power supplies";
this.batteryMenuItem.Name = "batteryMenuItem";
this.batteryMenuItem.Size = new System.Drawing.Size(180, 22);
this.batteryMenuItem.Text = "Batteries";
//
// MainForm
//
@@ -970,6 +979,7 @@ namespace LibreHardwareMonitor.UI
private ToolStripRadioButtonMenuItem timeWindow24hMenuItem;
private System.Windows.Forms.ToolStripMenuItem authWebServerMenuItem;
private System.Windows.Forms.ToolStripMenuItem psuMenuItem;
private System.Windows.Forms.ToolStripMenuItem batteryMenuItem;
private System.ComponentModel.BackgroundWorker backgroundUpdater;
}
}
+7
View File
@@ -50,6 +50,7 @@ namespace LibreHardwareMonitor.UI
private readonly UserOption _readHddSensors;
private readonly UserOption _readNicSensors;
private readonly UserOption _readPsuSensors;
private readonly UserOption _readBatterySensors;
private readonly UserOption _showGadget;
private UserRadioGroup _plotLocation;
@@ -262,6 +263,12 @@ namespace LibreHardwareMonitor.UI
_computer.IsPsuEnabled = _readPsuSensors.Value;
};
_readBatterySensors = new UserOption("batteryMenuItem", true, batteryMenuItem, _settings);
_readBatterySensors.Changed += delegate
{
_computer.IsBatteryEnabled = _readBatterySensors.Value;
};
_showGadget = new UserOption("gadgetMenuItem", false, gadgetMenuItem, _settings);
_showGadget.Changed += delegate
{
+2 -1
View File
@@ -171,7 +171,8 @@ namespace LibreHardwareMonitor.UI
{ SensorType.Factor, "1" },
{ SensorType.Power, "W" },
{ SensorType.Data, "GB" },
{ SensorType.Frequency, "Hz" }
{ SensorType.Frequency, "Hz" },
{ SensorType.Energy, "mWh" }
};
foreach (SensorType type in Enum.GetValues(typeof(SensorType)))
+3
View File
@@ -643,6 +643,9 @@ namespace LibreHardwareMonitor.UI
case SensorType.TimeSpan:
format = "{0:g}";
break;
case SensorType.Energy:
format = "{0:F0} mWh";
break;
}
if (sensor.SensorType == SensorType.Temperature && _unitManager.TemperatureUnit == TemperatureUnit.Fahrenheit)
+3
View File
@@ -76,6 +76,9 @@ namespace LibreHardwareMonitor.UI
case SensorType.TimeSpan:
Format = "{0:g}";
break;
case SensorType.Energy:
Format = "{0:F0} mWh";
break;
}
bool hidden = settings.GetValue(new Identifier(sensor.Identifier, "hidden").ToString(), sensor.IsDefaultHidden);
@@ -181,6 +181,7 @@ namespace LibreHardwareMonitor.UI
case SensorType.Power:
case SensorType.Data:
case SensorType.Load:
case SensorType.Energy:
return $"{Sensor.Value:F0}";
default:
return "-";
@@ -255,6 +256,7 @@ namespace LibreHardwareMonitor.UI
case SensorType.Power: format = "\n{0}: {1:F0} W"; break;
case SensorType.Data: format = "\n{0}: {1:F0} GB"; break;
case SensorType.Factor: format = "\n{0}: {1:F3} GB"; break;
case SensorType.Energy: format = "\n{0}: {0:F0} mWh"; break;
}
string formattedValue = string.Format(format, Sensor.Name, Sensor.Value);
+4
View File
@@ -31,6 +31,10 @@ namespace LibreHardwareMonitor.UI
Image = Utilities.EmbeddedResources.GetImage("voltage.png");
Text = "Currents";
break;
case SensorType.Energy:
Image = Utilities.EmbeddedResources.GetImage("battery.png");
Text = "Capacities";
break;
case SensorType.Clock:
Image = Utilities.EmbeddedResources.GetImage("clock.png");
Text = "Clocks";
@@ -643,6 +643,8 @@ namespace LibreHardwareMonitor.Utilities
return "nic.png";
case HardwareType.Psu:
return "power-supply.png";
case HardwareType.Battery:
return "battery.png";
default:
return "cpu.png";
}
@@ -0,0 +1,195 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
using System.Linq;
using System.Runtime.InteropServices;
using LibreHardwareMonitor.Interop;
using Microsoft.Win32.SafeHandles;
namespace LibreHardwareMonitor.Hardware.Battery
{
internal sealed class Battery : Hardware
{
private readonly SafeFileHandle _batteryHandle;
private readonly Kernel32.BATTERY_INFORMATION _batteryInformation;
private readonly uint _batteryTag;
private readonly Sensor _chargeDischargeCurrent;
private readonly Sensor _chargeDischargeRate;
private readonly Sensor _chargeLevel;
private readonly Sensor _degradationPercentage;
private readonly Sensor _designedCapacity;
private readonly Sensor _fullChargedCapacity;
private readonly Sensor _remainingCapacity;
private readonly Sensor _voltage;
public Battery
(
string name,
string manufacturer,
SafeFileHandle batteryHandle,
Kernel32.BATTERY_INFORMATION batteryInfo,
uint batteryTag,
ISettings settings) :
base(name, new Identifier("battery"), settings)
{
Name = name;
Manufacturer = manufacturer;
_batteryTag = batteryTag;
_batteryHandle = batteryHandle;
_batteryInformation = batteryInfo;
if (batteryInfo.Chemistry.SequenceEqual(new[] { 'P', 'b', 'A', 'c' }))
{
Chemistry = BatteryChemistry.LeadAcid;
}
else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'I', 'O', 'N' }) || batteryInfo.Chemistry.SequenceEqual(new[] { 'L', 'i', '-', 'I' }))
{
Chemistry = BatteryChemistry.LithiumIon;
}
else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'C', 'd' }))
{
Chemistry = BatteryChemistry.NickelCadmium;
}
else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'M', 'H' }))
{
Chemistry = BatteryChemistry.NickelMetalHydride;
}
else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'N', 'i', 'Z', 'n' }))
{
Chemistry = BatteryChemistry.NickelZinc;
}
else if (batteryInfo.Chemistry.SequenceEqual(new[] { 'R', 'A', 'M', '\x00' }))
{
Chemistry = BatteryChemistry.AlkalineManganese;
}
else
{
Chemistry = BatteryChemistry.Unknown;
}
DegradationLevel = 100f - (batteryInfo.FullChargedCapacity * 100f / batteryInfo.DesignedCapacity);
DesignedCapacity = batteryInfo.DesignedCapacity;
FullChargedCapacity = batteryInfo.FullChargedCapacity;
_chargeLevel = new Sensor("Charge Level", 0, SensorType.Level, this, settings);
ActivateSensor(_chargeLevel);
_voltage = new Sensor("Voltage", 1, SensorType.Voltage, this, settings);
ActivateSensor(_voltage);
_chargeDischargeCurrent = new Sensor("Current", 2, SensorType.Current, this, settings);
ActivateSensor(_chargeDischargeCurrent);
_designedCapacity = new Sensor("Designed Capacity", 3, SensorType.Energy, this, settings);
ActivateSensor(_designedCapacity);
_fullChargedCapacity = new Sensor("Full Charged Capacity", 4, SensorType.Energy, this, settings);
ActivateSensor(_fullChargedCapacity);
_remainingCapacity = new Sensor("Remaining Capacity", 5, SensorType.Energy, this, settings);
ActivateSensor(_remainingCapacity);
_chargeDischargeRate = new Sensor("Charge/Discharge Rate", 0, SensorType.Power, this, settings);
ActivateSensor(_chargeDischargeRate);
_degradationPercentage = new Sensor("Degradation Level", 0, SensorType.Level, this, settings);
ActivateSensor(_degradationPercentage);
}
public float ChargeDischargeCurrent { get; private set; }
public float ChargeDischargeRate { get; private set; }
public float ChargeLevel { get; private set; }
public BatteryChemistry Chemistry { get; }
public float DegradationLevel { get; }
public float DesignedCapacity { get; }
public float FullChargedCapacity { get; }
public override HardwareType HardwareType => HardwareType.Battery;
public string Manufacturer { get; }
public float RemainingCapacity { get; private set; }
public float Voltage { get; private set; }
public override void Update()
{
Kernel32.BATTERY_WAIT_STATUS bws = default;
bws.BatteryTag = _batteryTag;
Kernel32.BATTERY_STATUS batteryStatus = default;
if (Kernel32.DeviceIoControl(_batteryHandle,
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_STATUS,
ref bws,
Marshal.SizeOf(bws),
ref batteryStatus,
Marshal.SizeOf(batteryStatus),
out _,
IntPtr.Zero))
{
_designedCapacity.Value = Convert.ToSingle(_batteryInformation.DesignedCapacity);
_fullChargedCapacity.Value = Convert.ToSingle(_batteryInformation.FullChargedCapacity);
_remainingCapacity.Value = Convert.ToSingle(batteryStatus.Capacity);
RemainingCapacity = Convert.ToSingle(batteryStatus.Capacity);
_voltage.Value = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
Voltage = Convert.ToSingle(batteryStatus.Voltage) / 1000f;
_chargeLevel.Value = _remainingCapacity.Value * 100f / _fullChargedCapacity.Value;
ChargeLevel = (_remainingCapacity.Value * 100f / _fullChargedCapacity.Value).GetValueOrDefault();
ChargeDischargeRate = batteryStatus.Rate / 1000f;
switch (batteryStatus.Rate)
{
case > 0:
_chargeDischargeRate.Name = "Charge Rate";
_chargeDischargeRate.Value = batteryStatus.Rate / 1000f;
_chargeDischargeCurrent.Name = "Charge Current";
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
break;
case < 0:
_chargeDischargeRate.Name = "Discharge Rate";
_chargeDischargeRate.Value = Math.Abs(batteryStatus.Rate) / 1000f;
_chargeDischargeCurrent.Name = "Discharge Current";
_chargeDischargeCurrent.Value = _chargeDischargeRate.Value / _voltage.Value;
ChargeDischargeCurrent = (_chargeDischargeRate.Value / _voltage.Value).GetValueOrDefault();
break;
default:
_chargeDischargeRate.Name = "Charge/Discharge Rate";
_chargeDischargeRate.Value = 0f;
ChargeDischargeRate = 0f;
_chargeDischargeCurrent.Name = "Charge/Discharge Current";
_chargeDischargeCurrent.Value = 0f;
ChargeDischargeCurrent = 0f;
break;
}
_degradationPercentage.Value = 100f - (_fullChargedCapacity.Value * 100f / _designedCapacity.Value);
}
}
public override void Close()
{
base.Close();
_batteryHandle.Close();
}
}
}
@@ -0,0 +1,17 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
namespace LibreHardwareMonitor.Hardware.Battery;
internal enum BatteryChemistry
{
Unknown,
LeadAcid,
NickelCadmium,
NickelMetalHydride,
LithiumIon,
NickelZinc,
AlkalineManganese
}
@@ -0,0 +1,227 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using LibreHardwareMonitor.Interop;
using Microsoft.Win32.SafeHandles;
namespace LibreHardwareMonitor.Hardware.Battery
{
internal class BatteryGroup : IGroup
{
private readonly List<Battery> _hardware = new();
public unsafe BatteryGroup(ISettings settings)
{
// No implementation for battery information on Unix systems
if (Software.OperatingSystem.IsUnix)
return;
IntPtr hdev = SetupApi.SetupDiGetClassDevs(ref SetupApi.GUID_DEVICE_BATTERY, IntPtr.Zero, IntPtr.Zero, SetupApi.DIGCF_PRESENT | SetupApi.DIGCF_DEVICEINTERFACE);
if (hdev != SetupApi.INVALID_HANDLE_VALUE)
{
for (uint i = 0;; i++)
{
SetupApi.SP_DEVICE_INTERFACE_DATA did = default;
did.cbSize = (uint)Marshal.SizeOf(typeof(SetupApi.SP_DEVICE_INTERFACE_DATA));
if (!SetupApi.SetupDiEnumDeviceInterfaces(hdev,
IntPtr.Zero,
ref SetupApi.GUID_DEVICE_BATTERY,
i,
ref did))
{
if (Marshal.GetLastWin32Error() == SetupApi.ERROR_NO_MORE_ITEMS)
break;
}
else
{
SetupApi.SetupDiGetDeviceInterfaceDetail(hdev,
did,
IntPtr.Zero,
0,
out uint cbRequired,
IntPtr.Zero);
if (Marshal.GetLastWin32Error() == SetupApi.ERROR_INSUFFICIENT_BUFFER)
{
IntPtr pdidd = Kernel32.LocalAlloc(Kernel32.LPTR, cbRequired);
Marshal.WriteInt32(pdidd, Environment.Is64BitOperatingSystem ? 8 : 4); // cbSize.
if (SetupApi.SetupDiGetDeviceInterfaceDetail(hdev,
did,
pdidd,
cbRequired,
out _,
IntPtr.Zero))
{
string devicePath = new((char*)(pdidd + 4));
SafeFileHandle battery = Kernel32.CreateFile(devicePath, FileAccess.ReadWrite, FileShare.ReadWrite, IntPtr.Zero, FileMode.Open, FileAttributes.Normal, IntPtr.Zero);
if (!battery.IsInvalid)
{
Kernel32.BATTERY_QUERY_INFORMATION bqi = default;
uint dwWait = 0;
if (Kernel32.DeviceIoControl(battery,
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_TAG,
ref dwWait,
Marshal.SizeOf(dwWait),
ref bqi.BatteryTag,
Marshal.SizeOf(bqi.BatteryTag),
out _,
IntPtr.Zero))
{
Kernel32.BATTERY_INFORMATION bi = default;
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryInformation;
if (Kernel32.DeviceIoControl(battery,
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
ref bqi,
Marshal.SizeOf(bqi),
ref bi,
Marshal.SizeOf(bi),
out _,
IntPtr.Zero))
{
// Only batteries count.
if (bi.Capabilities == Kernel32.BatteryCapabilities.BATTERY_SYSTEM_BATTERY)
{
const int maxLoadString = 100;
IntPtr ptrDevName = Marshal.AllocCoTaskMem(maxLoadString);
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryDeviceName;
if (Kernel32.DeviceIoControl(battery,
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
ref bqi,
Marshal.SizeOf(bqi),
ptrDevName,
maxLoadString,
out _,
IntPtr.Zero))
{
IntPtr ptrManName = Marshal.AllocCoTaskMem(maxLoadString);
bqi.InformationLevel = Kernel32.BATTERY_QUERY_INFORMATION_LEVEL.BatteryManufactureName;
if (Kernel32.DeviceIoControl(battery,
Kernel32.IOCTL.IOCTL_BATTERY_QUERY_INFORMATION,
ref bqi,
Marshal.SizeOf(bqi),
ptrManName,
maxLoadString,
out _,
IntPtr.Zero))
{
string name = Marshal.PtrToStringUni(ptrDevName);
string manufacturer = Marshal.PtrToStringUni(ptrManName);
_hardware.Add(new Battery(name, manufacturer, battery, bi, bqi.BatteryTag, settings));
}
Marshal.FreeCoTaskMem(ptrManName);
}
Marshal.FreeCoTaskMem(ptrDevName);
}
}
}
}
}
Kernel32.LocalFree(pdidd);
}
}
}
SetupApi.SetupDiDestroyDeviceInfoList(hdev);
}
}
/// <inheritdoc />
public IReadOnlyList<IHardware> Hardware => _hardware;
/// <inheritdoc />
public void Close()
{
foreach (Battery battery in _hardware)
battery.Close();
}
/// <inheritdoc />
public string GetReport()
{
StringBuilder reportBuilder = new();
uint count = 1;
foreach (Battery bat in _hardware)
{
string chemistry = "Unknown";
switch (bat.Chemistry)
{
case BatteryChemistry.LeadAcid:
chemistry = "Lead Acid";
break;
case BatteryChemistry.NickelCadmium:
chemistry = "Nickel-Cadmium";
break;
case BatteryChemistry.NickelMetalHydride:
chemistry = "Nickel-Metal Hydride";
break;
case BatteryChemistry.LithiumIon:
chemistry = "Lithium Ion";
break;
case BatteryChemistry.NickelZinc:
chemistry = "Nickel-Zinc";
break;
case BatteryChemistry.AlkalineManganese:
chemistry = "Rechargeable Alkaline-Manganese";
break;
}
reportBuilder.Append("Battery #").Append(count).AppendLine(":")
.Append(" Name: ").AppendLine(bat.Name)
.Append(" Manufacturer: ").AppendLine(bat.Manufacturer)
.Append(" Chemistry: ").AppendLine(chemistry)
.Append(" Degradation Level: ").AppendFormat("{0:F2}", bat.DegradationLevel).AppendLine(" %")
.Append(" Designed Capacity: ").Append(bat.DesignedCapacity).AppendLine(" mWh")
.Append(" Full Charged Capacity: ").Append(bat.FullChargedCapacity).AppendLine(" mWh")
.Append(" Remaining Capacity: ").Append(bat.RemainingCapacity).AppendLine(" mWh")
.Append(" Charge Level: ").AppendFormat("{0:F2}", bat.RemainingCapacity * 100f / bat.FullChargedCapacity).AppendLine(" %")
.Append(" Voltage: ").AppendFormat("{0:F3}", bat.Voltage).AppendLine(" V");
switch (bat.ChargeDischargeRate)
{
case > 0:
reportBuilder.Append(" Charge Rate: ").AppendFormat("{0:F1}", bat.ChargeDischargeRate).AppendLine(" W")
.Append(" Charge Current: ").AppendFormat("{0:F3}", bat.ChargeDischargeRate / bat.Voltage).AppendLine(" A");
break;
case < 0:
reportBuilder.Append(" Discharge Rate: ").AppendFormat("{0:F1}", Math.Abs(bat.ChargeDischargeRate)).AppendLine(" W")
.Append(" Discharge Current: ").AppendFormat("{0:F3}", Math.Abs(bat.ChargeDischargeRate) / bat.Voltage).AppendLine(" A");
break;
default:
reportBuilder.AppendLine(" Charge/Discharge Rate: 0 W")
.AppendLine(" Charge/Discharge Current: 0 A");
break;
}
reportBuilder.AppendLine();
count++;
}
return reportBuilder.ToString();
}
}
}
+87 -68
View File
@@ -8,7 +8,7 @@ using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Security.Permissions;
using LibreHardwareMonitor.Hardware.Battery;
using LibreHardwareMonitor.Hardware.Controller.AeroCool;
using LibreHardwareMonitor.Hardware.Controller.AquaComputer;
using LibreHardwareMonitor.Hardware.Controller.Heatmaster;
@@ -28,16 +28,11 @@ namespace LibreHardwareMonitor.Hardware
/// </summary>
public class Computer : IComputer
{
/// <inheritdoc />
public event HardwareEventHandler HardwareAdded;
/// <inheritdoc />
public event HardwareEventHandler HardwareRemoved;
private readonly object _lock = new object();
private readonly List<IGroup> _groups = new List<IGroup>();
private readonly List<IGroup> _groups = new();
private readonly object _lock = new();
private readonly ISettings _settings;
private bool _batteryEnabled;
private bool _controllerEnabled;
private bool _cpuEnabled;
private bool _gpuEnabled;
@@ -45,13 +40,12 @@ namespace LibreHardwareMonitor.Hardware
private bool _motherboardEnabled;
private bool _networkEnabled;
private bool _open;
private bool _storageEnabled;
private bool _psuEnabled;
private SMBios _smbios;
private bool _storageEnabled;
/// <summary>
/// Creates a new <see cref="IComputer"/> instance with basic initial <see cref="Settings"/>.
/// Creates a new <see cref="IComputer" /> instance with basic initial <see cref="Settings" />.
/// </summary>
public Computer()
{
@@ -59,14 +53,20 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// Creates a new <see cref="IComputer"/> instance with additional <see cref="ISettings"/>.
/// Creates a new <see cref="IComputer" /> instance with additional <see cref="ISettings" />.
/// </summary>
/// <param name="settings">Computer settings that will be transferred to each <see cref="IHardware"/>.</param>
/// <param name="settings">Computer settings that will be transferred to each <see cref="IHardware" />.</param>
public Computer(ISettings settings)
{
_settings = settings ?? new Settings();
}
/// <inheritdoc />
public event HardwareEventHandler HardwareAdded;
/// <inheritdoc />
public event HardwareEventHandler HardwareRemoved;
/// <inheritdoc />
public IList<IHardware> Hardware
{
@@ -74,7 +74,7 @@ namespace LibreHardwareMonitor.Hardware
{
lock (_lock)
{
List<IHardware> list = new List<IHardware>();
List<IHardware> list = new();
foreach (IGroup group in _groups)
list.AddRange(group.Hardware);
@@ -84,35 +84,25 @@ namespace LibreHardwareMonitor.Hardware
}
}
/// <summary>
/// Contains computer information table read in accordance with <see href="https://www.dmtf.org/standards/smbios">System Management BIOS (SMBIOS) Reference Specification</see>.
/// </summary>
public SMBios SMBios
{
get
{
if (!_open)
throw new InvalidOperationException("SMBIOS cannot be accessed before opening.");
return _smbios;
}
}
/// <inheritdoc />
public bool IsCpuEnabled
public bool IsBatteryEnabled
{
get { return _cpuEnabled; }
get { return _batteryEnabled; }
set
{
if (_open && value != _cpuEnabled)
if (_open && value != _batteryEnabled)
{
if (value)
Add(new CPU.CpuGroup(_settings));
{
Add(new BatteryGroup(_settings));
}
else
RemoveType<CPU.CpuGroup>();
{
RemoveType<BatteryGroup>();
}
}
_cpuEnabled = value;
_batteryEnabled = value;
}
}
@@ -146,6 +136,24 @@ namespace LibreHardwareMonitor.Hardware
}
}
/// <inheritdoc />
public bool IsCpuEnabled
{
get { return _cpuEnabled; }
set
{
if (_open && value != _cpuEnabled)
{
if (value)
Add(new CPU.CpuGroup(_settings));
else
RemoveType<CPU.CpuGroup>();
}
_cpuEnabled = value;
}
}
/// <inheritdoc />
public bool IsGpuEnabled
{
@@ -224,6 +232,28 @@ namespace LibreHardwareMonitor.Hardware
}
}
/// <inheritdoc />
public bool IsPsuEnabled
{
get { return _psuEnabled; }
set
{
if (_open && value != _psuEnabled)
{
if (value)
{
Add(new CorsairPsuGroup(_settings));
}
else
{
RemoveType<CorsairPsuGroup>();
}
}
_psuEnabled = value;
}
}
/// <inheritdoc />
public bool IsStorageEnabled
{
@@ -242,24 +272,17 @@ namespace LibreHardwareMonitor.Hardware
}
}
/// <inheritdoc />
public bool IsPsuEnabled
/// <summary>
/// Contains computer information table read in accordance with <see href="https://www.dmtf.org/standards/smbios">System Management BIOS (SMBIOS) Reference Specification</see>.
/// </summary>
public SMBios SMBios
{
get { return _psuEnabled; }
set
get
{
if (_open && value != _psuEnabled)
{
if (value)
{
Add(new CorsairPsuGroup(_settings));
}
else
{
RemoveType<CorsairPsuGroup>();
}
}
_psuEnabled = value;
if (!_open)
throw new InvalidOperationException("SMBIOS cannot be accessed before opening.");
return _smbios;
}
}
@@ -268,7 +291,7 @@ namespace LibreHardwareMonitor.Hardware
{
lock (_lock)
{
using StringWriter w = new StringWriter(CultureInfo.InvariantCulture);
using StringWriter w = new(CultureInfo.InvariantCulture);
w.WriteLine();
w.WriteLine(nameof(LibreHardwareMonitor) + " Report");
@@ -341,7 +364,7 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// Triggers the <see cref="IVisitor.VisitComputer"/> method for the given observer.
/// Triggers the <see cref="IVisitor.VisitComputer" /> method for the given observer.
/// </summary>
/// <param name="visitor">Observer who call to devices.</param>
public void Accept(IVisitor visitor)
@@ -349,12 +372,11 @@ namespace LibreHardwareMonitor.Hardware
if (visitor == null)
throw new ArgumentNullException(nameof(visitor));
visitor.VisitComputer(this);
}
/// <summary>
/// Triggers the <see cref="IElement.Accept"/> method with the given visitor for each device in each group.
/// Triggers the <see cref="IElement.Accept" /> method with the given visitor for each device in each group.
/// </summary>
/// <param name="visitor">Observer who call to devices.</param>
public void Traverse(IVisitor visitor)
@@ -387,13 +409,11 @@ namespace LibreHardwareMonitor.Hardware
if (group == null)
return;
lock (_lock)
{
if (_groups.Contains(group))
return;
_groups.Add(group);
if (group is IHardwareChanged hardwareChanged)
@@ -417,7 +437,6 @@ namespace LibreHardwareMonitor.Hardware
if (!_groups.Contains(group))
return;
_groups.Remove(group);
if (group is IHardwareChanged hardwareChanged)
@@ -438,7 +457,7 @@ namespace LibreHardwareMonitor.Hardware
private void RemoveType<T>() where T : IGroup
{
List<T> list = new List<T>();
List<T> list = new();
lock (_lock)
{
@@ -454,14 +473,14 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// If hasn't been opened before, opens <see cref="SMBios"/>, <see cref="Ring0"/>, <see cref="OpCode"/> and triggers the private <see cref="AddGroups"/> method depending on which categories are enabled.
/// If hasn't been opened before, opens <see cref="SMBios" />, <see cref="Ring0" />, <see cref="OpCode" /> and triggers the private <see cref="AddGroups" /> method depending on which categories are
/// enabled.
/// </summary>
public void Open()
{
if (_open)
return;
_smbios = new SMBios();
Ring0.Open();
@@ -506,6 +525,9 @@ namespace LibreHardwareMonitor.Hardware
if (_psuEnabled)
Add(new CorsairPsuGroup(_settings));
if (_batteryEnabled)
Add(new BatteryGroup(_settings));
}
private static void NewSection(TextWriter writer)
@@ -523,7 +545,6 @@ namespace LibreHardwareMonitor.Hardware
if (c == 0)
return a.Index.CompareTo(b.Index);
return c;
}
@@ -584,14 +605,13 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// If opened before, removes all <see cref="IGroup"/> and triggers <see cref="OpCode.Close"/>, <see cref="InpOut.Close"/> and <see cref="Ring0.Close"/>.
/// If opened before, removes all <see cref="IGroup" /> and triggers <see cref="OpCode.Close" />, <see cref="InpOut.Close" /> and <see cref="Ring0.Close" />.
/// </summary>
public void Close()
{
if (!_open)
return;
lock (_lock)
{
while (_groups.Count > 0)
@@ -610,14 +630,13 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// If opened before, removes all <see cref="IGroup"/> and recreates it.
/// If opened before, removes all <see cref="IGroup" /> and recreates it.
/// </summary>
public void Reset()
{
if (!_open)
return;
RemoveGroups();
AddGroups();
}
@@ -635,7 +654,7 @@ namespace LibreHardwareMonitor.Hardware
}
/// <summary>
/// <see cref="Computer"/> specific additional settings passed to its <see cref="IHardware"/>.
/// <see cref="Computer" /> specific additional settings passed to its <see cref="IHardware" />.
/// </summary>
private class Settings : ISettings
{
@@ -21,6 +21,7 @@ namespace LibreHardwareMonitor.Hardware
Network,
Cooler,
EmbeddedController,
Psu
Psu,
Battery
}
}
+72 -56
View File
@@ -20,77 +20,93 @@ namespace LibreHardwareMonitor.Hardware
public interface IComputer : IElement
{
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Cpu"/> devices should be enabled and updated.
/// Triggered when a new <see cref="IHardware" /> is registered.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsCpuEnabled { get; }
event HardwareEventHandler HardwareAdded;
/// <summary>
/// Gets or sets a value indicating whether collecting information about:
/// <list>
/// <item><see cref="LibreHardwareMonitor.Hardware.Controller.TBalancer.TBalancerGroup"/></item>
/// <item><see cref="LibreHardwareMonitor.Hardware.Controller.Heatmaster.HeatmasterGroup"/></item>
/// <item><see cref="LibreHardwareMonitor.Hardware.Controller.AquaComputer.AquaComputerGroup"/></item>
/// <item><see cref="LibreHardwareMonitor.Hardware.Controller.AeroCool.AeroCoolGroup"/></item>
/// <item><see cref="LibreHardwareMonitor.Hardware.Controller.Nzxt.NzxtGroup"/></item>
/// </list>
/// devices should be enabled and updated.
/// Triggered when a <see cref="IHardware" /> is removed.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsControllerEnabled { get; }
event HardwareEventHandler HardwareRemoved;
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.GpuAmd"/> or <see cref="HardwareType.GpuNvidia"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsGpuEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Storage"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsStorageEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Motherboard"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsMotherboardEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Network"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsNetworkEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Memory"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsMemoryEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Psu"/> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true"/> if a given category of devices is already enabled.</returns>
bool IsPsuEnabled { get; }
/// <summary>
/// Gets a list of all known <see cref="IHardware"/>.
/// <para>Can be updated by <see cref="IVisitor"/>.</para>
/// Gets a list of all known <see cref="IHardware" />.
/// <para>Can be updated by <see cref="IVisitor" />.</para>
/// </summary>
/// <returns>List of all enabled devices.</returns>
IList<IHardware> Hardware { get; }
/// <summary>
/// Triggered when a new <see cref="IHardware"/> is registered.
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Battery" /> devices should be enabled and updated.
/// </summary>
event HardwareEventHandler HardwareAdded;
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsBatteryEnabled { get; }
/// <summary>
/// Triggered when a <see cref="IHardware"/> is removed.
/// Gets or sets a value indicating whether collecting information about:
/// <list>
/// <item>
/// <see cref="Controller.TBalancer.TBalancerGroup" />
/// </item>
/// <item>
/// <see cref="Controller.Heatmaster.HeatmasterGroup" />
/// </item>
/// <item>
/// <see cref="Controller.AquaComputer.AquaComputerGroup" />
/// </item>
/// <item>
/// <see cref="Controller.AeroCool.AeroCoolGroup" />
/// </item>
/// <item>
/// <see cref="Controller.Nzxt.NzxtGroup" />
/// </item>
/// </list>
/// devices should be enabled and updated.
/// </summary>
event HardwareEventHandler HardwareRemoved;
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsControllerEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Cpu" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsCpuEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.GpuAmd" /> or <see cref="HardwareType.GpuNvidia" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsGpuEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Memory" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsMemoryEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Motherboard" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsMotherboardEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Network" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsNetworkEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Psu" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsPsuEnabled { get; }
/// <summary>
/// Gets or sets a value indicating whether collecting information about <see cref="HardwareType.Storage" /> devices should be enabled and updated.
/// </summary>
/// <returns><see langword="true" /> if a given category of devices is already enabled.</returns>
bool IsStorageEnabled { get; }
/// <summary>
/// Generates full LibreHardwareMonitor report for devices that have been enabled.
@@ -30,6 +30,7 @@ namespace LibreHardwareMonitor.Hardware
SmallData, // MB = 2^20 Bytes
Throughput, // B/s
TimeSpan, // Seconds
Energy // milliwatt-hour (mWh)
}
/// <summary>
+135 -1
View File
@@ -26,6 +26,9 @@ namespace LibreHardwareMonitor.Interop
internal const byte SMART_LBA_MID = 0x4F;
internal const byte SMART_LBA_HI_EXCEEDED = 0x2C;
internal const byte SMART_LBA_MID_EXCEEDED = 0xF4;
internal const uint LPTR = 0x0000 | 0x0040;
private const string DllName = "kernel32.dll";
[Flags]
@@ -203,6 +206,64 @@ namespace LibreHardwareMonitor.Interop
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl
(
SafeFileHandle hDevice,
IOCTL dwIoControlCode,
ref BATTERY_QUERY_INFORMATION lpInBuffer,
int nInBufferSize,
ref BATTERY_INFORMATION lpOutBuffer,
int nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl
(
SafeFileHandle hDevice,
IOCTL dwIoControlCode,
ref uint lpInBuffer,
int nInBufferSize,
ref uint lpOutBuffer,
int nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl
(
SafeFileHandle hDevice,
IOCTL dwIoControlCode,
ref BATTERY_WAIT_STATUS lpInBuffer,
int nInBufferSize,
ref BATTERY_STATUS lpOutBuffer,
int nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool DeviceIoControl
(
SafeFileHandle hDevice,
IOCTL dwIoControlCode,
ref BATTERY_QUERY_INFORMATION lpInBuffer,
int nInBufferSize,
IntPtr lpOutBuffer,
int nOutBufferSize,
out uint lpBytesReturned,
IntPtr lpOverlapped);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr LocalAlloc(uint uFlags, ulong uBytes);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi)]
internal static extern IntPtr LocalFree(IntPtr hMem);
[DllImport(DllName, SetLastError = true)]
internal static extern void RtlZeroMemory(IntPtr Destination, int Length);
@@ -291,7 +352,80 @@ namespace LibreHardwareMonitor.Interop
IOCTL_SCSI_MINIPORT = 0x04d008,
IOCTL_SCSI_PASS_THROUGH_DIRECT = 0x04d014,
IOCTL_SCSI_GET_ADDRESS = 0x41018,
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400
IOCTL_STORAGE_QUERY_PROPERTY = 0x2D1400,
IOCTL_BATTERY_QUERY_TAG = 0x294040,
IOCTL_BATTERY_QUERY_INFORMATION = 0x294044,
IOCTL_BATTERY_QUERY_STATUS = 0x29404C
}
[Flags]
internal enum BatteryCapabilities : uint
{
BATTERY_CAPACITY_RELATIVE = 0x40000000,
BATTERY_IS_SHORT_TERM = 0x20000000,
BATTERY_SET_CHARGE_SUPPORTED = 0x00000001,
BATTERY_SET_DISCHARGE_SUPPORTED = 0x00000002,
BATTERY_SYSTEM_BATTERY = 0x80000000
}
internal enum BATTERY_QUERY_INFORMATION_LEVEL
{
BatteryInformation,
BatteryGranularityInformation,
BatteryTemperature,
BatteryEstimatedTime,
BatteryDeviceName,
BatteryManufactureDate,
BatteryManufactureName,
BatteryUniqueID,
BatterySerialNumber
}
[StructLayout(LayoutKind.Sequential)]
internal struct BATTERY_QUERY_INFORMATION
{
public uint BatteryTag;
public BATTERY_QUERY_INFORMATION_LEVEL InformationLevel;
public uint AtRate;
}
[StructLayout(LayoutKind.Sequential)]
internal struct BATTERY_INFORMATION
{
public BatteryCapabilities Capabilities;
public byte Technology;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3)]
public byte[] Reserved;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 4)]
public char[] Chemistry;
public uint DesignedCapacity;
public uint FullChargedCapacity;
public uint DefaultAlert1;
public uint DefaultAlert2;
public uint CriticalBias;
public uint CycleCount;
}
[StructLayout(LayoutKind.Sequential)]
internal struct BATTERY_WAIT_STATUS
{
public uint BatteryTag;
public uint Timeout;
public uint PowerState;
public uint LowCapacity;
public uint HighCapacity;
}
[StructLayout(LayoutKind.Sequential)]
internal struct BATTERY_STATUS
{
public uint PowerState;
public uint Capacity;
public uint Voltage;
public int Rate;
}
[Flags]
@@ -0,0 +1,50 @@
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// Copyright (C) LibreHardwareMonitor and Contributors.
// All Rights Reserved.
using System;
using System.Runtime.InteropServices;
namespace LibreHardwareMonitor.Interop
{
internal class SetupApi
{
internal const int ERROR_INSUFFICIENT_BUFFER = 122;
internal const int ERROR_NO_MORE_ITEMS = 259;
internal const int DIGCF_PRESENT = 0x00000002;
internal const int DIGCF_DEVICEINTERFACE = 0x00000010;
internal static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);
internal static Guid GUID_DEVICE_BATTERY = new Guid(0x72631e54, 0x78A4, 0x11d0, 0xbc, 0xf7, 0x00, 0xaa, 0x00, 0xb7, 0xb3, 0x2a);
private const string DllName = "SetupAPI.dll";
[StructLayout(LayoutKind.Sequential)]
internal struct SP_DEVICE_INTERFACE_DATA
{
public uint cbSize;
public Guid InterfaceClassGuid;
public uint Flags;
public IntPtr Reserved;
}
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
internal static extern IntPtr SetupDiGetClassDevs(ref Guid ClassGuid, IntPtr Enumerator, IntPtr hwndParent, uint Flags);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetupDiEnumDeviceInterfaces(IntPtr DeviceInfoSet, IntPtr DeviceInfoData, ref Guid InterfaceClassGuid, uint MemberIndex, ref SP_DEVICE_INTERFACE_DATA DeviceInterfaceData);
[DllImport(DllName, SetLastError = true, EntryPoint = "SetupDiGetDeviceInterfaceDetailW", CharSet = CharSet.Unicode)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetupDiGetDeviceInterfaceDetail(IntPtr DeviceInfoSet,
in SP_DEVICE_INTERFACE_DATA DeviceInterfaceData,
[Out, Optional] IntPtr DeviceInterfaceDetailData,
uint DeviceInterfaceDetailDataSize,
out uint RequiredSize,
IntPtr DeviceInfoData = default);
[DllImport(DllName, CallingConvention = CallingConvention.Winapi, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static extern bool SetupDiDestroyDeviceInfoList(IntPtr DeviceInfoSet);
}
}