#include <windows.h>
#include <batclass.h>
-#define GBS_HASBATTERY 0x1
-#define GBS_ONBATTERY 0x2
-
int br_icons[5] = { IDI_BATTCAP0, IDI_BATTCAP1, IDI_BATTCAP2, IDI_BATTCAP3, IDI_BATTCAP4 }; // battery mode icons.
int bc_icons[5] = { IDI_BATTCHA0, IDI_BATTCHA1, IDI_BATTCHA2, IDI_BATTCHA3, IDI_BATTCHA4 }; // charging mode icons.
} PWRSCHEMECONTEXT, *PPWRSCHEMECONTEXT;
CString g_strTooltip;
-static float g_batCap = 0;
static HICON g_hIconBattery = NULL;
static BOOL g_IsRunning = FALSE;
-/*++
-* @name GetBatteryState
-*
-* Enumerates the available battery devices and provides the remaining capacity.
-*
-* @param cap
-* If no error occurs, then this will contain average remaining capacity.
-* @param dwResult
-* Helps in making battery type checks.
-* {
-* Returned value includes GBS_HASBATTERY if the system has a non-UPS battery,
-* and GBS_ONBATTERY if the system is running on a battery.
-* dwResult & GBS_ONBATTERY means we have not yet found AC power.
-* dwResult & GBS_HASBATTERY means we have found a non-UPS battery.
-* }
-*
-* @return The error code.
-*
-*--*/
-static HRESULT GetBatteryState(float& cap, DWORD& dwResult)
-{
- cap = 0;
- dwResult = GBS_ONBATTERY;
-
- HDEVINFO hdev = SetupDiGetClassDevs(&GUID_DEVCLASS_BATTERY, 0, 0, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
- if (INVALID_HANDLE_VALUE == hdev)
- return E_HANDLE;
-
- // Limit search to 100 batteries max
- for (int idev = 0, count = 0; idev < 100; idev++)
- {
- SP_DEVICE_INTERFACE_DATA did = { 0 };
- did.cbSize = sizeof(did);
-
- if (SetupDiEnumDeviceInterfaces(hdev, 0, &GUID_DEVCLASS_BATTERY, idev, &did))
- {
- DWORD cbRequired = 0;
-
- SetupDiGetDeviceInterfaceDetail(hdev, &did, 0, 0, &cbRequired, 0);
- if (ERROR_INSUFFICIENT_BUFFER == GetLastError())
- {
- PSP_DEVICE_INTERFACE_DETAIL_DATA pdidd = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LPTR, cbRequired);
- if (pdidd)
- {
- pdidd->cbSize = sizeof(*pdidd);
- if (SetupDiGetDeviceInterfaceDetail(hdev, &did, pdidd, cbRequired, &cbRequired, 0))
- {
- // Enumerated a battery. Ask it for information.
- HANDLE hBattery = CreateFile(pdidd->DevicePath, GENERIC_READ | GENERIC_WRITE,
- FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
-
- if (INVALID_HANDLE_VALUE != hBattery)
- {
- // Ask the battery for its tag.
- BATTERY_QUERY_INFORMATION bqi = { 0 };
-
- DWORD dwWait = 0;
- DWORD dwOut;
-
- if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_TAG, &dwWait, sizeof(dwWait), &bqi.BatteryTag,
- sizeof(bqi.BatteryTag), &dwOut, NULL) && bqi.BatteryTag)
- {
- // With the tag, you can query the battery info.
- BATTERY_INFORMATION bi = { 0 };
- bqi.InformationLevel = BatteryInformation;
-
- if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_INFORMATION, &bqi, sizeof(bqi), &bi,
- sizeof(bi), &dwOut, NULL))
- {
- // Only non-UPS system batteries count
- if (bi.Capabilities & BATTERY_SYSTEM_BATTERY)
- {
- if (!(bi.Capabilities & BATTERY_IS_SHORT_TERM))
- dwResult |= GBS_HASBATTERY;
-
- // Query the battery status.
- BATTERY_WAIT_STATUS bws = { 0 };
- bws.BatteryTag = bqi.BatteryTag;
-
- BATTERY_STATUS bs;
- if (DeviceIoControl(hBattery, IOCTL_BATTERY_QUERY_STATUS, &bws, sizeof(bws),
- &bs, sizeof(bs), &dwOut, NULL))
- {
- if (bs.PowerState & BATTERY_POWER_ON_LINE)
- dwResult &= ~GBS_ONBATTERY;
-
- // Take average of total capacity of batteries detected!
- cap = cap*(count)+(float)bs.Capacity / bi.FullChargedCapacity * 100;
- cap /= count + 1;
- count++;
- }
- }
- }
- }
- CloseHandle(hBattery);
- }
- }
- LocalFree(pdidd);
- }
- }
- }
- else if (ERROR_NO_MORE_ITEMS == GetLastError())
- {
- break; // Enumeration failed - perhaps we're out of items
- }
- }
- SetupDiDestroyDeviceInfoList(hdev);
-
- // Final cleanup: If we didn't find a battery, then presume that we
- // are on AC power.
-
- if (!(dwResult & GBS_HASBATTERY))
- dwResult &= ~GBS_ONBATTERY;
-
- return S_OK;
-}
/*++
* @name Quantize
*
* @param p
* Should be a quantity in percentage.
-* @param lvl
-* Quantization level (this excludes base level 0, which will always be present), default is 10.
*
* @return Nearest quantized level, can be directly used as array index based on context.
*
-*--*/
-static UINT Quantize(float p, UINT lvl = 10)
-{
- int i = 0;
- float f, q = (float)100 / lvl, d = q / 2;
- for (f = 0; f < p; f += q, i++);
-
- if ((f - d) <= p)
- return i;
- else
- return i - 1;
-/*
@remarks This function uses centred/symmetric logic for quantization.
For the case of lvl = 4, You will get following integer levels if given (p) value falls in between the range partitions:
0 <= p < 12.5 : returns 0; (corresponding to 0% centre)
37.5 <= p < 62.5 : returns 2; (corresponding to 50% centre)
62.5 <= p < 87.5 : returns 3; (corresponding to 75% centre)
87.5 <= p <= 100 : returns 4; (corresponding to 100% centre)
-*/
+ *--*/
+static UINT Quantize(BYTE p)
+{
+ if (p <= 12)
+ return 0;
+ else if (p > 12 && p <= 37)
+ return 1;
+ else if (p > 37 && p <= 62)
+ return 2;
+ else if (p > 62 && p <= 87)
+ return 3;
+ else
+ return 4;
}
/*++
*
*--*/
static HICON DynamicLoadIcon(HINSTANCE hinst)
-{
+{
+ SYSTEM_POWER_STATUS PowerStatus;
HICON hBatIcon;
- float cap = 0;
- DWORD dw = 0;
UINT index = -1;
- HRESULT hr = GetBatteryState(cap, dw);
- if (!FAILED(hr) && (dw & GBS_HASBATTERY))
- {
- index = Quantize(cap, 4);
- g_batCap = cap;
- }
- else
+ if (!GetSystemPowerStatus(&PowerStatus) ||
+ PowerStatus.ACLineStatus == AC_LINE_UNKNOWN ||
+ PowerStatus.BatteryFlag == BATTERY_FLAG_UNKNOWN)
{
- g_batCap = 0;
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_BATTCAP_ERR));
g_strTooltip.LoadStringW(IDS_PWR_UNKNOWN_REMAINING);
return hBatIcon;
}
- if (dw & GBS_ONBATTERY)
+ if (((PowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0) &&
+ ((PowerStatus.BatteryFlag & BATTERY_FLAG_CHARGING) == BATTERY_FLAG_CHARGING))
{
+ index = Quantize(PowerStatus.BatteryLifePercent);
+ hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(bc_icons[index]));
+ g_strTooltip.Format(IDS_PWR_CHARGING, PowerStatus.BatteryLifePercent);
+ }
+ else if (((PowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) == 0) &&
+ ((PowerStatus.BatteryFlag & BATTERY_FLAG_CHARGING) == 0))
+ {
+ index = Quantize(PowerStatus.BatteryLifePercent);
hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(br_icons[index]));
- g_strTooltip.Format(IDS_PWR_PERCENT_REMAINING, cap);
+ g_strTooltip.Format(IDS_PWR_PERCENT_REMAINING, PowerStatus.BatteryLifePercent);
}
else
{
- hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(bc_icons[index]));
- g_strTooltip.Format(IDS_PWR_CHARGING, cap);
+ hBatIcon = LoadIcon(hinst, MAKEINTRESOURCE(IDI_POWER_AC));
+ g_strTooltip.LoadStringW(IDS_PWR_AC);
}
return hBatIcon;