windows平台用winapi读取电池状态最轻量可靠,但getsystempowerstatus仅提供基础信息;需配合callntpowerinformation获取designcapacity与fullchargecapacity计算健康度,linux则通过/sys/class/power_supply/下energy_full与energy_full_design计算,跨平台须分系统实现。

Windows平台用WinAPI直接读取电池状态
Windows系统下,GetSystemPowerStatus 是最轻量、最可靠的方式,它能返回当前电池的充电状态、剩余电量和关键健康指标。这个函数不依赖WMI或第三方库,调用快、权限要求低(普通用户即可),但要注意它只提供“是否存在电池”“当前电量百分比”“是否在充电”等基础信息,不直接暴露电池循环次数或设计容量百分比这类“健康度”数值。
真正反映健康状态的关键字段是 BatteryLifePercent 和 BackupBatteryLifePercent,但它们只是当前可用容量占“上次校准后记录的满充容量”的比例——而这个“满充容量”本身可能已衰减。所以你需要配合 GetPwrCapabilities 判断是否支持高级电池信息,再用 CallNtPowerInformation(需 POWER_INFORMATION_LEVEL::BatteryInformation)获取原始容量数据。
-
GetSystemPowerStatus返回的ACLineStatus为1表示市电接入,0表示仅靠电池 -
BatteryFlag的值为128(即BATTERY_FLAG_NO_BATTERY)说明系统未检测到可管理电池(比如某些台式机主板或老旧笔记本) - 若
BatteryLifeTime为-1,表示剩余时间未知(常见于电池老化或驱动未上报)
用 CallNtPowerInformation 获取原始电池容量参数
这是获取电池健康核心数据的唯一可行路径:设计容量(DesignCapacity)、当前满充容量(FullChargeCapacity)、当前剩余容量(RemainingCapacity)。三者一除,就能算出当前健康度:(FullChargeCapacity / DesignCapacity) * 100。但这个 API 是 NT 内核级调用,需要链接 powrprof.lib,且返回结构体 BATTERY_INFORMATION 中的字段单位是毫瓦时(mWh),不是百分比。
容易踩的坑是直接用 BATTERY_INFORMATION 而没检查 CallNtPowerInformation 返回值:失败时返回非零值,且多数情况下是因为权限不足或驱动未实现该信息级别(尤其在 OEM 定制 BIOS 的机器上)。
- 必须用
POWER_INFORMATION_LEVEL::BatteryInformation作为第一个参数,不能用BatteryEstimatedTime或其他枚举值 - 传入的缓冲区大小必须精确为
sizeof(BATTERY_INFORMATION),多一字节或少一字节都会导致访问违规 -
FullChargeCapacity可能为0,此时计算健康度会除零——需提前判断并跳过
Linux 下通过 sysfs 解析电池健康数据
Linux 没有统一 API,所有信息都暴露在 /sys/class/power_supply/ 下。典型路径是 /sys/class/power_supply/BAT0/,里面 capacity 是当前电量百分比,energy_full_design 是出厂设计容量(单位 μWh),energy_full 是当前可充入的最大能量(单位也是 μWh)。健康度 = energy_full / energy_full_design * 100。
但注意:不同厂商命名不一致,BAT0 可能是 BAT1 或 axp288_fuel_gauge;有些设备把设计容量放在 charge_full_design(单位 μAh),这时就得结合电压估算(voltage_now)才能换算成能量值。
- 读取
/sys/class/power_supply/*/online可判断是否插电,值为1表示 AC 在线 -
status文件内容可能是Charging、Discharging或Full,不是布尔值 - 某些 ARM 笔记本(如 Pinebook Pro)的电池驱动不提供
energy_full_design,只能退而求其次用charge_full_design+ 平均电压粗略估算
跨平台方案为什么几乎不可行
没有标准 C++ 库能抽象 Windows 的 CallNtPowerInformation 和 Linux 的 sysfs 路径差异。Boost.Process 或 std::filesystem 都无法绕过操作系统对电源硬件的访问限制。试图封装成统一接口,最终要么在 Windows 上漏掉健康度计算,要么在 Linux 上硬编码 BAT0 导致在双电池机型(如 ThinkPad T系列)上只读到主电池、忽略辅电池。
更现实的做法是编译期条件判断:#ifdef _WIN32 走 WinAPI 分支,#ifdef __linux__ 走 sysfs 文件读取,各自独立处理错误路径。不要尝试用 WMI 或 D-Bus 做“通用层”——WMI 在 Windows Server Core 版本里默认禁用,D-Bus 在嵌入式 Linux 里常被裁剪。
真正难的不是读数据,而是解释数据:同一块电池,在 Windows 驱动里上报的 FullChargeCapacity 和 Linux sysfs 里的 energy_full 常有 3%~5% 差异,这是驱动层校准逻辑不同导致的,没法靠代码修正,只能接受这个浮动范围。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











