[NTOS:PO] Implement SystemBatteryState in NtPowerInformation

This should get us proper battery status display.
This commit is contained in:
Timo Kreuzer
2025-09-13 11:38:38 +03:00
parent 3a6e0d4b65
commit 571ac5e608
2 changed files with 131 additions and 10 deletions
+129 -9
View File
@@ -784,6 +784,115 @@ NtInitiatePowerAction(IN POWER_ACTION SystemAction,
return STATUS_NOT_IMPLEMENTED;
}
static
NTSTATUS
PopQueryBatteryState(
_Out_ PSYSTEM_BATTERY_STATE BatteryState)
{
static const UNICODE_STRING CompBattDeviceName =
RTL_CONSTANT_STRING(L"\\Device\\CompositeBattery");
OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES(
&CompBattDeviceName, OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE);
HANDLE CompBattHandle;
IO_STATUS_BLOCK IoStatusBlock;
BATTERY_QUERY_INFORMATION BatteryQueryInfo = {0};
BATTERY_INFORMATION BatteryInfo = { 0 };
BATTERY_STATUS BatteryStatus;
NTSTATUS Status;
/* Open the CompositeBattery device */
Status = ZwOpenFile(&CompBattHandle,
GENERIC_READ | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_SYNCHRONOUS_IO_NONALERT);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to open CompositeBattery device: Status: 0x%08lX\n", Status);
return Status;
}
/* Query the battery tag */
ULONG Wait = 0;
Status = ZwDeviceIoControlFile(CompBattHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BATTERY_QUERY_TAG,
&Wait,
sizeof(Wait),
&BatteryQueryInfo.BatteryTag,
sizeof(BatteryQueryInfo.BatteryTag));
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query battery tag: Status: 0x%08lX\n", Status);
goto Exit;
}
/* Query the battery information */
BatteryQueryInfo.InformationLevel = BatteryInformation;
Status = ZwDeviceIoControlFile(CompBattHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BATTERY_QUERY_INFORMATION,
&BatteryQueryInfo,
sizeof(BatteryQueryInfo),
&BatteryInfo,
sizeof(BatteryInfo));
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query battery information: Status: 0x%08lX\n", Status);
}
/* Query the battery status */
BATTERY_WAIT_STATUS BatteryWait = {0};
BatteryWait.BatteryTag = BatteryQueryInfo.BatteryTag;
BatteryWait.PowerState = 0xF ; // Wait for all power states
BatteryWait.HighCapacity = MAXULONG;
Status = ZwDeviceIoControlFile(CompBattHandle,
NULL,
NULL,
NULL,
&IoStatusBlock,
IOCTL_BATTERY_QUERY_STATUS,
&BatteryWait,
sizeof(BatteryWait),
&BatteryStatus,
sizeof(BatteryStatus));
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query battery status: Status: 0x%08lX\n", Status);
goto Exit;
}
RtlZeroMemory(BatteryState, sizeof(*BatteryState));
BatteryState->BatteryPresent = TRUE;
BatteryState->AcOnLine = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_POWER_ON_LINE);
BatteryState->Charging = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_CHARGING);
BatteryState->Discharging = BooleanFlagOn(BatteryStatus.PowerState, BATTERY_DISCHARGING);
BatteryState->MaxCapacity = BatteryInfo.FullChargedCapacity;
BatteryState->RemainingCapacity = BatteryStatus.Capacity;
BatteryState->Rate = BatteryStatus.Rate;
if (BatteryState->Discharging && BatteryStatus.Rate < 0)
{
BatteryState->EstimatedTime =
3600 * BatteryInfo.FullChargedCapacity / -BatteryStatus.Rate;
}
else
{
BatteryState->EstimatedTime = 0;
}
Exit:
ZwClose(CompBattHandle);
return Status;
}
/*
* @unimplemented
*/
@@ -824,23 +933,34 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
{
case SystemBatteryState:
{
PSYSTEM_BATTERY_STATE BatteryState = (PSYSTEM_BATTERY_STATE)OutputBuffer;
SYSTEM_BATTERY_STATE BatteryState;
if (InputBuffer != NULL)
return STATUS_INVALID_PARAMETER;
if (OutputBufferLength < sizeof(SYSTEM_BATTERY_STATE))
return STATUS_BUFFER_TOO_SMALL;
if (PopCapabilities.SystemBatteriesPresent)
{
/* Open the battery driver and query the battery state */
Status = PopQueryBatteryState(&BatteryState);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to query battery state: Status: 0x%08X\n", Status);
return Status;
}
}
else
{
/* No batteries present, set defaults */
RtlZeroMemory(&BatteryState, sizeof(BatteryState));
BatteryState.AcOnLine = TRUE;
}
_SEH2_TRY
{
/* Just zero the struct */
RtlZeroMemory(BatteryState, sizeof(*BatteryState));
BatteryState->EstimatedTime = MAXULONG;
BatteryState->BatteryPresent = PopCapabilities.SystemBatteriesPresent;
// BatteryState->AcOnLine = TRUE;
// BatteryState->MaxCapacity = ;
// BatteryState->RemainingCapacity = ;
/* Copy the battery state to the output buffer */
RtlCopyMemory(OutputBuffer, &BatteryState, sizeof(BatteryState));
Status = STATUS_SUCCESS;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+2 -1
View File
@@ -386,7 +386,8 @@ typedef struct {
BOOLEAN BatteryPresent;
BOOLEAN Charging;
BOOLEAN Discharging;
BOOLEAN Spare1[4];
BOOLEAN Spare1[3];
UCHAR Tag;
ULONG MaxCapacity;
ULONG RemainingCapacity;
ULONG Rate;