@@ -784,6 +784,115 @@ NtInitiatePowerAction(IN POWER_ACTION SystemAction,
784784 return STATUS_NOT_IMPLEMENTED ;
785785}
786786
787+ static
788+ NTSTATUS
789+ PopQueryBatteryState (
790+ _Out_ PSYSTEM_BATTERY_STATE BatteryState )
791+ {
792+ static const UNICODE_STRING CompBattDeviceName =
793+ RTL_CONSTANT_STRING (L"\\Device\\CompositeBattery" );
794+ OBJECT_ATTRIBUTES ObjectAttributes = RTL_CONSTANT_OBJECT_ATTRIBUTES (
795+ & CompBattDeviceName , OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE );
796+ HANDLE CompBattHandle ;
797+ IO_STATUS_BLOCK IoStatusBlock ;
798+ BATTERY_QUERY_INFORMATION BatteryQueryInfo = {0 };
799+ BATTERY_INFORMATION BatteryInfo = { 0 };
800+ BATTERY_STATUS BatteryStatus ;
801+ NTSTATUS Status ;
802+
803+ /* Open the CompositeBattery device */
804+ Status = ZwOpenFile (& CompBattHandle ,
805+ GENERIC_READ | SYNCHRONIZE ,
806+ & ObjectAttributes ,
807+ & IoStatusBlock ,
808+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
809+ FILE_SYNCHRONOUS_IO_NONALERT );
810+ if (!NT_SUCCESS (Status ))
811+ {
812+ DPRINT1 ("Failed to open CompositeBattery device: Status: 0x%08lX\n" , Status );
813+ return Status ;
814+ }
815+
816+ /* Query the battery tag */
817+ ULONG Wait = 0 ;
818+ Status = ZwDeviceIoControlFile (CompBattHandle ,
819+ NULL ,
820+ NULL ,
821+ NULL ,
822+ & IoStatusBlock ,
823+ IOCTL_BATTERY_QUERY_TAG ,
824+ & Wait ,
825+ sizeof (Wait ),
826+ & BatteryQueryInfo .BatteryTag ,
827+ sizeof (BatteryQueryInfo .BatteryTag ));
828+ if (!NT_SUCCESS (Status ))
829+ {
830+ DPRINT1 ("Failed to query battery tag: Status: 0x%08lX\n" , Status );
831+ goto Exit ;
832+ }
833+
834+ /* Query the battery information */
835+ BatteryQueryInfo .InformationLevel = BatteryInformation ;
836+ Status = ZwDeviceIoControlFile (CompBattHandle ,
837+ NULL ,
838+ NULL ,
839+ NULL ,
840+ & IoStatusBlock ,
841+ IOCTL_BATTERY_QUERY_INFORMATION ,
842+ & BatteryQueryInfo ,
843+ sizeof (BatteryQueryInfo ),
844+ & BatteryInfo ,
845+ sizeof (BatteryInfo ));
846+ if (!NT_SUCCESS (Status ))
847+ {
848+ DPRINT1 ("Failed to query battery information: Status: 0x%08lX\n" , Status );
849+ }
850+
851+ /* Query the battery status */
852+ BATTERY_WAIT_STATUS BatteryWait = {0 };
853+ BatteryWait .BatteryTag = BatteryQueryInfo .BatteryTag ;
854+ BatteryWait .PowerState = 0xF ; // Wait for all power states
855+ BatteryWait .HighCapacity = MAXULONG ;
856+ Status = ZwDeviceIoControlFile (CompBattHandle ,
857+ NULL ,
858+ NULL ,
859+ NULL ,
860+ & IoStatusBlock ,
861+ IOCTL_BATTERY_QUERY_STATUS ,
862+ & BatteryWait ,
863+ sizeof (BatteryWait ),
864+ & BatteryStatus ,
865+ sizeof (BatteryStatus ));
866+ if (!NT_SUCCESS (Status ))
867+ {
868+ DPRINT1 ("Failed to query battery status: Status: 0x%08lX\n" , Status );
869+ goto Exit ;
870+ }
871+
872+ RtlZeroMemory (BatteryState , sizeof (* BatteryState ));
873+ BatteryState -> BatteryPresent = TRUE;
874+ BatteryState -> AcOnLine = BooleanFlagOn (BatteryStatus .PowerState , BATTERY_POWER_ON_LINE );
875+ BatteryState -> Charging = BooleanFlagOn (BatteryStatus .PowerState , BATTERY_CHARGING );
876+ BatteryState -> Discharging = BooleanFlagOn (BatteryStatus .PowerState , BATTERY_DISCHARGING );
877+ BatteryState -> MaxCapacity = BatteryInfo .FullChargedCapacity ;
878+ BatteryState -> RemainingCapacity = BatteryStatus .Capacity ;
879+ BatteryState -> Rate = BatteryStatus .Rate ;
880+ if (BatteryState -> Discharging && BatteryStatus .Rate < 0 )
881+ {
882+ BatteryState -> EstimatedTime =
883+ 3600 * BatteryInfo .FullChargedCapacity / - BatteryStatus .Rate ;
884+ }
885+ else
886+ {
887+ BatteryState -> EstimatedTime = 0 ;
888+ }
889+
890+ Exit :
891+ ZwClose (CompBattHandle );
892+ return Status ;
893+ }
894+
895+
787896/*
788897 * @unimplemented
789898 */
@@ -824,23 +933,34 @@ NtPowerInformation(IN POWER_INFORMATION_LEVEL PowerInformationLevel,
824933 {
825934 case SystemBatteryState :
826935 {
827- PSYSTEM_BATTERY_STATE BatteryState = ( PSYSTEM_BATTERY_STATE ) OutputBuffer ;
936+ SYSTEM_BATTERY_STATE BatteryState ;
828937
829938 if (InputBuffer != NULL )
830939 return STATUS_INVALID_PARAMETER ;
831940 if (OutputBufferLength < sizeof (SYSTEM_BATTERY_STATE ))
832941 return STATUS_BUFFER_TOO_SMALL ;
833942
834- _SEH2_TRY
943+ if ( PopCapabilities . SystemBatteriesPresent )
835944 {
836- /* Just zero the struct */
837- RtlZeroMemory (BatteryState , sizeof (* BatteryState ));
838- BatteryState -> EstimatedTime = MAXULONG ;
839- BatteryState -> BatteryPresent = PopCapabilities .SystemBatteriesPresent ;
840- // BatteryState->AcOnLine = TRUE;
841- // BatteryState->MaxCapacity = ;
842- // BatteryState->RemainingCapacity = ;
945+ /* Open the battery driver and query the battery state */
946+ Status = PopQueryBatteryState (& BatteryState );
947+ if (!NT_SUCCESS (Status ))
948+ {
949+ DPRINT1 ("Failed to query battery state: Status: 0x%08X\n" , Status );
950+ return Status ;
951+ }
952+ }
953+ else
954+ {
955+ /* No batteries present, set defaults */
956+ RtlZeroMemory (& BatteryState , sizeof (BatteryState ));
957+ BatteryState .AcOnLine = TRUE;
958+ }
843959
960+ _SEH2_TRY
961+ {
962+ /* Copy the battery state to the output buffer */
963+ RtlCopyMemory (OutputBuffer , & BatteryState , sizeof (BatteryState ));
844964 Status = STATUS_SUCCESS ;
845965 }
846966 _SEH2_EXCEPT (EXCEPTION_EXECUTE_HANDLER )
0 commit comments