@@ -30,137 +30,146 @@ static inline void wrapSetupDiDestroyDeviceInfoList(HDEVINFO* hdev)
3030 SetupDiDestroyDeviceInfoList (* hdev );
3131}
3232
33- const char * ffDetectBattery (FFBatteryOptions * options , FFlist * results )
33+ static const char * detectWithSetupApi (FFBatteryOptions * options , FFlist * results )
3434{
35- if (options -> useSetupApi )
35+ //https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
36+ HDEVINFO hdev __attribute__((__cleanup__ (wrapSetupDiDestroyDeviceInfoList ))) =
37+ SetupDiGetClassDevsW (& GUID_DEVCLASS_BATTERY , 0 , 0 , DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
38+ if (hdev == INVALID_HANDLE_VALUE )
39+ return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed" ;
40+
41+ SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof (did ) };
42+ for (DWORD idev = 0 ; SetupDiEnumDeviceInterfaces (hdev , NULL , & GUID_DEVCLASS_BATTERY , idev , & did ); idev ++ )
3643 {
37- //https://learn.microsoft.com/en-us/windows/win32/power/enumerating-battery-devices
38- HDEVINFO hdev __attribute__((__cleanup__ (wrapSetupDiDestroyDeviceInfoList ))) =
39- SetupDiGetClassDevsW (& GUID_DEVCLASS_BATTERY , 0 , 0 , DIGCF_PRESENT | DIGCF_DEVICEINTERFACE );
40- if (hdev == INVALID_HANDLE_VALUE )
41- return "SetupDiGetClassDevsW(&GUID_DEVCLASS_BATTERY) failed" ;
42-
43- SP_DEVICE_INTERFACE_DATA did = { .cbSize = sizeof (did ) };
44- for (DWORD idev = 0 ; SetupDiEnumDeviceInterfaces (hdev , NULL , & GUID_DEVCLASS_BATTERY , idev , & did ); idev ++ )
44+ DWORD cbRequired = 0 ;
45+ SetupDiGetDeviceInterfaceDetailW (hdev , & did , NULL , 0 , & cbRequired , NULL ); //Fail with not enough buffer
46+ SP_DEVICE_INTERFACE_DETAIL_DATA_W * FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W * )malloc (cbRequired );
47+ if (!pdidd )
48+ break ; //Out of memory
49+
50+ pdidd -> cbSize = sizeof (* pdidd );
51+ if (!SetupDiGetDeviceInterfaceDetailW (hdev , & did , pdidd , cbRequired , & cbRequired , NULL ))
52+ continue ;
53+
54+ HANDLE __attribute__((__cleanup__ (wrapCloseHandle ))) hBattery =
55+ CreateFileW (pdidd -> DevicePath , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
56+
57+ if (hBattery == INVALID_HANDLE_VALUE )
58+ continue ;
59+
60+ BATTERY_QUERY_INFORMATION bqi = { .InformationLevel = BatteryInformation };
61+
62+ DWORD dwWait = 0 ;
63+ DWORD dwOut ;
64+
65+ if (!DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_TAG , & dwWait , sizeof (dwWait ), & bqi .BatteryTag , sizeof (bqi .BatteryTag ), & dwOut , NULL ) && bqi .BatteryTag )
66+ continue ;
67+
68+ BATTERY_INFORMATION bi = {0 };
69+ if (!DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), & bi , sizeof (bi ), & dwOut , NULL ))
70+ continue ;
71+
72+ if (!(bi .Capabilities & BATTERY_SYSTEM_BATTERY ))
73+ continue ;
74+
75+ FFBatteryResult * battery = (FFBatteryResult * )ffListAdd (results );
76+
77+ if (memcmp (bi .Chemistry , "PbAc" , 4 ) == 0 )
78+ ffStrbufInitS (& battery -> technology , "Lead Acid" );
79+ else if (memcmp (bi .Chemistry , "LION" , 4 ) == 0 || memcmp (bi .Chemistry , "Li-I" , 4 ) == 0 )
80+ ffStrbufInitS (& battery -> technology , "Lithium Ion" );
81+ else if (memcmp (bi .Chemistry , "NiCd" , 4 ) == 0 )
82+ ffStrbufInitS (& battery -> technology , "Nickel Cadmium" );
83+ else if (memcmp (bi .Chemistry , "NiMH" , 4 ) == 0 )
84+ ffStrbufInitS (& battery -> technology , "Nickel Metal Hydride" );
85+ else if (memcmp (bi .Chemistry , "NiZn" , 4 ) == 0 )
86+ ffStrbufInitS (& battery -> technology , "Nickel Zinc" );
87+ else if (memcmp (bi .Chemistry , "RAM\0" , 4 ) == 0 )
88+ ffStrbufInitS (& battery -> technology , "Rechargeable Alkaline-Manganese" );
89+ else
90+ ffStrbufInitS (& battery -> technology , "Unknown" );
91+
92+ {
93+ ffStrbufInit (& battery -> modelName );
94+ bqi .InformationLevel = BatteryDeviceName ;
95+ wchar_t name [64 ];
96+ if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), name , sizeof (name ), & dwOut , NULL ))
97+ ffStrbufSetWS (& battery -> modelName , name );
98+ }
99+
100+ {
101+ ffStrbufInit (& battery -> manufacturer );
102+ bqi .InformationLevel = BatteryManufactureName ;
103+ wchar_t name [64 ];
104+ if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), name , sizeof (name ), & dwOut , NULL ))
105+ ffStrbufSetWS (& battery -> manufacturer , name );
106+ }
107+
108+ battery -> cycleCount = bi .CycleCount ;
109+
110+ battery -> temperature = 0.0 /0.0 ;
111+ if (options -> temp )
112+ {
113+ bqi .InformationLevel = BatteryTemperature ;
114+ ULONG temp ;
115+ if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), & temp , sizeof (temp ), & dwOut , NULL ))
116+ battery -> temperature = temp ;
117+ }
118+
45119 {
46- DWORD cbRequired = 0 ;
47- SetupDiGetDeviceInterfaceDetailW (hdev , & did , NULL , 0 , & cbRequired , NULL ); //Fail with not enough buffer
48- SP_DEVICE_INTERFACE_DETAIL_DATA_W * FF_AUTO_FREE pdidd = (SP_DEVICE_INTERFACE_DETAIL_DATA_W * )malloc (cbRequired );
49- if (!pdidd )
50- break ; //Out of memory
51-
52- pdidd -> cbSize = sizeof (* pdidd );
53- if (!SetupDiGetDeviceInterfaceDetailW (hdev , & did , pdidd , cbRequired , & cbRequired , NULL ))
54- continue ;
55-
56- HANDLE __attribute__((__cleanup__ (wrapCloseHandle ))) hBattery =
57- CreateFileW (pdidd -> DevicePath , GENERIC_READ , FILE_SHARE_READ , NULL , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , NULL );
58-
59- if (hBattery == INVALID_HANDLE_VALUE )
60- continue ;
61-
62- BATTERY_QUERY_INFORMATION bqi = { .InformationLevel = BatteryInformation };
63-
64- DWORD dwWait = 0 ;
65- DWORD dwOut ;
66-
67- if (!DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_TAG , & dwWait , sizeof (dwWait ), & bqi .BatteryTag , sizeof (bqi .BatteryTag ), & dwOut , NULL ) && bqi .BatteryTag )
68- continue ;
69-
70- BATTERY_INFORMATION bi = {0 };
71- if (!DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), & bi , sizeof (bi ), & dwOut , NULL ))
72- continue ;
73-
74- if (!(bi .Capabilities & BATTERY_SYSTEM_BATTERY ))
75- continue ;
76-
77- FFBatteryResult * battery = (FFBatteryResult * )ffListAdd (results );
78-
79- if (memcmp (bi .Chemistry , "PbAc" , 4 ) == 0 )
80- ffStrbufInitS (& battery -> technology , "Lead Acid" );
81- else if (memcmp (bi .Chemistry , "LION" , 4 ) == 0 || memcmp (bi .Chemistry , "Li-I" , 4 ) == 0 )
82- ffStrbufInitS (& battery -> technology , "Lithium Ion" );
83- else if (memcmp (bi .Chemistry , "NiCd" , 4 ) == 0 )
84- ffStrbufInitS (& battery -> technology , "Nickel Cadmium" );
85- else if (memcmp (bi .Chemistry , "NiMH" , 4 ) == 0 )
86- ffStrbufInitS (& battery -> technology , "Nickel Metal Hydride" );
87- else if (memcmp (bi .Chemistry , "NiZn" , 4 ) == 0 )
88- ffStrbufInitS (& battery -> technology , "Nickel Zinc" );
89- else if (memcmp (bi .Chemistry , "RAM\0" , 4 ) == 0 )
90- ffStrbufInitS (& battery -> technology , "Rechargeable Alkaline-Manganese" );
120+ BATTERY_STATUS bs ;
121+ BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi .BatteryTag };
122+ if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_STATUS , & bws , sizeof (bws ), & bs , sizeof (bs ), & dwOut , NULL ) && bs .Capacity != BATTERY_UNKNOWN_CAPACITY )
123+ battery -> capacity = bs .Capacity * 100.0 / bi .FullChargedCapacity ;
91124 else
92- ffStrbufInitS (& battery -> technology , "Unknown" );
93-
94- {
95- ffStrbufInit (& battery -> modelName );
96- bqi .InformationLevel = BatteryDeviceName ;
97- wchar_t name [64 ];
98- if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), name , sizeof (name ), & dwOut , NULL ))
99- ffStrbufSetWS (& battery -> modelName , name );
100- }
101-
102- {
103- ffStrbufInit (& battery -> manufacturer );
104- bqi .InformationLevel = BatteryManufactureName ;
105- wchar_t name [64 ];
106- if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), name , sizeof (name ), & dwOut , NULL ))
107- ffStrbufSetWS (& battery -> manufacturer , name );
108- }
109-
110- battery -> temperature = 0.0 /0.0 ;
111- if (options -> temp )
112- {
113- bqi .InformationLevel = BatteryTemperature ;
114- ULONG temp ;
115- if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_INFORMATION , & bqi , sizeof (bqi ), & temp , sizeof (temp ), & dwOut , NULL ))
116- battery -> temperature = temp ;
117- }
118-
119- {
120- BATTERY_STATUS bs ;
121- BATTERY_WAIT_STATUS bws = { .BatteryTag = bqi .BatteryTag };
122- if (DeviceIoControl (hBattery , IOCTL_BATTERY_QUERY_STATUS , & bws , sizeof (bws ), & bs , sizeof (bs ), & dwOut , NULL ) && bs .Capacity != BATTERY_UNKNOWN_CAPACITY )
123- battery -> capacity = bs .Capacity * 100.0 / bi .FullChargedCapacity ;
124- else
125- battery -> capacity = 0 ;
126-
127- ffStrbufInit (& battery -> status );
128- if (bs .PowerState & BATTERY_POWER_ON_LINE )
129- ffStrbufAppendS (& battery -> status , "AC Connected, " );
130- if (bs .PowerState & BATTERY_DISCHARGING )
131- ffStrbufAppendS (& battery -> status , "Discharging, " );
132- if (bs .PowerState & BATTERY_CHARGING )
133- ffStrbufAppendS (& battery -> status , "Charging" );
134- if (bs .PowerState & BATTERY_CRITICAL )
135- ffStrbufAppendS (& battery -> status , "Critical, " );
136- ffStrbufTrimRight (& battery -> status , ' ' );
137- ffStrbufTrimRight (& battery -> status , ',' );
138- }
125+ battery -> capacity = 0 ;
126+
127+ ffStrbufInit (& battery -> status );
128+ if (bs .PowerState & BATTERY_POWER_ON_LINE )
129+ ffStrbufAppendS (& battery -> status , "AC Connected, " );
130+ if (bs .PowerState & BATTERY_DISCHARGING )
131+ ffStrbufAppendS (& battery -> status , "Discharging, " );
132+ if (bs .PowerState & BATTERY_CHARGING )
133+ ffStrbufAppendS (& battery -> status , "Charging, " );
134+ if (bs .PowerState & BATTERY_CRITICAL )
135+ ffStrbufAppendS (& battery -> status , "Critical, " );
136+ ffStrbufTrimRight (& battery -> status , ' ' );
137+ ffStrbufTrimRight (& battery -> status , ',' );
139138 }
140139 }
141- else
140+ return NULL ;
141+ }
142+
143+ static const char * detectWithNtApi (FFBatteryOptions * options , FFlist * results )
144+ {
145+ SYSTEM_BATTERY_STATE info ;
146+ if (NT_SUCCESS (NtPowerInformation (SystemBatteryState , NULL , 0 , & info , sizeof (info ))) && info .BatteryPresent )
142147 {
143- SYSTEM_BATTERY_STATE info ;
144- if (NT_SUCCESS (NtPowerInformation (SystemBatteryState , NULL , 0 , & info , sizeof (info ))) && info .BatteryPresent )
148+ FFBatteryResult * battery = (FFBatteryResult * )ffListAdd (results );
149+ ffStrbufInit (& battery -> modelName );
150+ ffStrbufInit (& battery -> manufacturer );
151+ ffStrbufInit (& battery -> technology );
152+ ffStrbufInit (& battery -> status );
153+ battery -> temperature = 0.0 /0.0 ;
154+ battery -> cycleCount = 0 ;
155+
156+ battery -> capacity = info .RemainingCapacity * 100.0 / info .MaxCapacity ;
157+ if (info .AcOnLine )
145158 {
146- FFBatteryResult * battery = (FFBatteryResult * )ffListAdd (results );
147- ffStrbufInit (& battery -> modelName );
148- ffStrbufInit (& battery -> manufacturer );
149- ffStrbufInit (& battery -> technology );
150- ffStrbufInit (& battery -> status );
151- battery -> temperature = 0.0 /0.0 ;
152-
153- battery -> capacity = info .RemainingCapacity * 100.0 / info .MaxCapacity ;
154- if (info .AcOnLine )
155- {
156- ffStrbufAppendS (& battery -> status , "AC Connected" );
157- if (info .Charging )
158- ffStrbufAppendS (& battery -> status , ", Charging" );
159- }
160- else if (info .Discharging )
161- ffStrbufAppendS (& battery -> status , "Discharging" );
159+ ffStrbufAppendS (& battery -> status , "AC Connected" );
160+ if (info .Charging )
161+ ffStrbufAppendS (& battery -> status , ", Charging" );
162162 }
163+ else if (info .Discharging )
164+ ffStrbufAppendS (& battery -> status , "Discharging" );
165+ return NULL ;
163166 }
167+ return "NtPowerInformation(SystemBatteryState) failed" ;
168+ }
164169
165- return NULL ;
170+ const char * ffDetectBattery (FFBatteryOptions * options , FFlist * results )
171+ {
172+ return true
173+ ? detectWithSetupApi (options , results )
174+ : detectWithNtApi (options , results );
166175}
0 commit comments