523 lines
14 KiB
C
523 lines
14 KiB
C
/*******************************************************************************
|
|
*
|
|
* (C) COPYRIGHT MICROSOFT CORP., 1996
|
|
*
|
|
* TITLE: BATSTATE.C
|
|
*
|
|
* VERSION: 2.0
|
|
*
|
|
* AUTHOR: ReedB
|
|
*
|
|
* DATE: 17 Oct, 1996
|
|
*
|
|
* DESCRIPTION:
|
|
* BATSTATE.C contains helper function which maintain the global battery
|
|
* state list.
|
|
*
|
|
*******************************************************************************/
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
|
|
#include <dbt.h>
|
|
#include <devioctl.h>
|
|
#include <ntpoapi.h>
|
|
#include <poclass.h>
|
|
|
|
#include "powrprofp.h"
|
|
#include "batmeter.h"
|
|
|
|
// Simulated battery only for debug build.
|
|
#ifndef DEBUG
|
|
#undef SIM_BATTERY
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* G L O B A L D A T A
|
|
*
|
|
*******************************************************************************/
|
|
|
|
// Global battery state list. This list has the composite system battery state
|
|
// as it's always present head. individual battery devices are linked to this
|
|
// head. Use WalkBatteryState(ALL, ... to walk the entire list, including the
|
|
// head. Use WalkBatteryState(DEVICES, ... to walk just the device list. If a
|
|
// battery is in this list, it's displayable. g_ulBatCount is the count of
|
|
// battery devices in this list. The composite battery is not counted.
|
|
|
|
extern BATTERY_STATE g_bs;
|
|
extern ULONG g_ulBatCount;
|
|
extern HWND g_hwndBatMeter;
|
|
|
|
#ifdef WINNT
|
|
/*******************************************************************************
|
|
*
|
|
* RegisterForDeviceNotification
|
|
*
|
|
* DESCRIPTION:
|
|
* Do registration for WM_DEVICECHANGED.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL RegisterForDeviceNotification(PBATTERY_STATE pbs)
|
|
{
|
|
DEV_BROADCAST_HANDLE dbh;
|
|
|
|
memset(&dbh, 0, sizeof(DEV_BROADCAST_HANDLE));
|
|
|
|
dbh.dbch_size = sizeof(DEV_BROADCAST_HANDLE);
|
|
dbh.dbch_devicetype = DBT_DEVTYP_HANDLE;
|
|
dbh.dbch_handle = pbs->hDevice;
|
|
|
|
if (!g_hwndBatMeter) {
|
|
DebugPrint( "RegisterForDeviceNotification, NULL g_hwndBatMeter");
|
|
return FALSE;
|
|
}
|
|
|
|
pbs->hDevNotify = RegisterDeviceNotification(g_hwndBatMeter,
|
|
&dbh,
|
|
DEVICE_NOTIFY_WINDOW_HANDLE);
|
|
|
|
if (!pbs->hDevNotify) {
|
|
DebugPrint( "RegisterDeviceNotification failed");
|
|
return FALSE;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UnregisterForDeviceNotification
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void UnregisterForDeviceNotification(PBATTERY_STATE pbs)
|
|
{
|
|
if (pbs->hDevNotify) {
|
|
UnregisterDeviceNotification(pbs->hDevNotify);
|
|
pbs->hDevNotify = NULL;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SystemPowerStatusToBatteryState
|
|
*
|
|
* DESCRIPTION:
|
|
* Fill in BATTERY_STATE fields based on passed SYSTEM_POWER_STATUS.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
void SystemPowerStatusToBatteryState(
|
|
LPSYSTEM_POWER_STATUS lpsps,
|
|
PBATTERY_STATE pbs
|
|
)
|
|
{
|
|
pbs->ulPowerState = 0;
|
|
if (lpsps->ACLineStatus == AC_LINE_ONLINE) {
|
|
pbs->ulPowerState |= BATTERY_POWER_ON_LINE;
|
|
}
|
|
if (lpsps->BatteryFlag & BATTERY_FLAG_CHARGING) {
|
|
pbs->ulPowerState |= BATTERY_CHARGING;
|
|
}
|
|
if (lpsps->BatteryFlag & BATTERY_FLAG_CRITICAL) {
|
|
pbs->ulPowerState |= BATTERY_CRITICAL;
|
|
}
|
|
pbs->ulBatLifePercent = lpsps->BatteryLifePercent;
|
|
pbs->ulBatLifeTime = lpsps->BatteryLifeTime;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* WalkBatteryState
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL WalkBatteryState(
|
|
PBATTERY_STATE pbsStart,
|
|
WALKENUMPROC pfnWalkEnumProc,
|
|
HWND hWnd,
|
|
LPARAM lParam1,
|
|
LPARAM lParam2
|
|
)
|
|
{
|
|
PBATTERY_STATE pbsTmp;
|
|
|
|
while (pbsStart) {
|
|
// Save the next entry in case the current one is deleted.
|
|
pbsTmp = pbsStart->bsNext;
|
|
if (!pfnWalkEnumProc(pbsStart, hWnd, lParam1, lParam2)) {
|
|
return FALSE;
|
|
}
|
|
pbsStart = pbsTmp;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* UpdateBatInfoProc
|
|
*
|
|
* DESCRIPTION:
|
|
* Updates battery information for an individual battery device.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL UpdateBatInfoProc(
|
|
PBATTERY_STATE pbs,
|
|
HWND hWnd,
|
|
LPARAM lParam1,
|
|
LPARAM lParam2
|
|
)
|
|
{
|
|
DWORD dwByteCount, dwIOCTL, dwWait;
|
|
BATTERY_STATUS bs;
|
|
BATTERY_WAIT_STATUS bws;
|
|
BATTERY_INFORMATION bi;
|
|
BATTERY_QUERY_INFORMATION bqi;
|
|
|
|
if (pbs->hDevice == INVALID_HANDLE_VALUE) {
|
|
DebugPrint( "UpdateBatInfoProc, Bad battery driver handle, LastError: 0x%X", GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
// If no tag, then don't update the battery info.
|
|
dwIOCTL = IOCTL_BATTERY_QUERY_TAG;
|
|
dwWait = 0;
|
|
if (DeviceIoControl(pbs->hDevice, dwIOCTL,
|
|
&dwWait, sizeof(dwWait),
|
|
&(pbs->ulTag), sizeof(ULONG),
|
|
&dwByteCount, NULL)) {
|
|
|
|
bqi.BatteryTag = pbs->ulTag;
|
|
bqi.InformationLevel = BatteryInformation;
|
|
bqi.AtRate = 0;
|
|
|
|
dwIOCTL = IOCTL_BATTERY_QUERY_INFORMATION;
|
|
if (DeviceIoControl(pbs->hDevice, dwIOCTL,
|
|
&bqi, sizeof(bqi),
|
|
&bi, sizeof(bi),
|
|
&dwByteCount, NULL)) {
|
|
|
|
if (bi.FullChargedCapacity != UNKNOWN_CAPACITY) {
|
|
pbs->ulFullChargedCapacity = bi.FullChargedCapacity;
|
|
}
|
|
else {
|
|
pbs->ulFullChargedCapacity = bi.DesignedCapacity;
|
|
}
|
|
|
|
memset(&bws, 0, sizeof(BATTERY_WAIT_STATUS));
|
|
bws.BatteryTag = pbs->ulTag;
|
|
dwIOCTL = IOCTL_BATTERY_QUERY_STATUS;
|
|
if (DeviceIoControl(pbs->hDevice, dwIOCTL,
|
|
&bws, sizeof(BATTERY_WAIT_STATUS),
|
|
&bs, sizeof(BATTERY_STATUS),
|
|
&dwByteCount, NULL)) {
|
|
|
|
pbs->ulPowerState = bs.PowerState;
|
|
if (pbs->ulFullChargedCapacity < bs.Capacity) {
|
|
pbs->ulFullChargedCapacity = bs.Capacity;
|
|
DebugPrint( "UpdateBatInfoProc, unable to calculate ulFullChargedCapacity");
|
|
}
|
|
if (pbs->ulFullChargedCapacity == 0) {
|
|
pbs->ulBatLifePercent = 0;
|
|
}
|
|
else {
|
|
pbs->ulBatLifePercent =
|
|
(100 * bs.Capacity) / pbs->ulFullChargedCapacity;
|
|
}
|
|
return TRUE;
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
pbs->ulTag = BATTERY_TAG_INVALID;
|
|
|
|
// No battery tag, that's ok, the user may have removed the battery.
|
|
if (GetLastError() == ERROR_FILE_NOT_FOUND) {
|
|
return TRUE;
|
|
}
|
|
}
|
|
DebugPrint( "UpdateBatInfoProc, IOCTL: %X Failure, BatNum: %d, LastError: %d\n", dwIOCTL, pbs->ulBatNum, GetLastError());
|
|
return FALSE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SimUpdateBatInfoProc
|
|
*
|
|
* DESCRIPTION:
|
|
* Simulate the update of battery information for an individual batter device.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL SimUpdateBatInfoProc(
|
|
PBATTERY_STATE pbs,
|
|
HWND hWnd,
|
|
LPARAM lParam1,
|
|
LPARAM lParam2
|
|
)
|
|
{
|
|
pbs->ulTag = pbs->ulBatNum;
|
|
if (pbs->ulBatNum == 1) {
|
|
pbs->ulFullChargedCapacity = 2000;
|
|
pbs->ulFullChargedCapacity = 1991;
|
|
pbs->ulPowerState = BATTERY_CHARGING | BATTERY_POWER_ON_LINE;
|
|
pbs->ulBatLifePercent = 75;
|
|
}
|
|
else {
|
|
pbs->ulFullChargedCapacity = 3000;
|
|
pbs->ulFullChargedCapacity = 2991;
|
|
pbs->ulPowerState = BATTERY_DISCHARGING | BATTERY_CRITICAL;
|
|
pbs->ulBatLifePercent = 3;
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* AddBatteryStateDevice
|
|
*
|
|
* DESCRIPTION:
|
|
* Add only displayable batteries to the battery list. New entry is appended
|
|
* to battery state list.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
PBATTERY_STATE AddBatteryStateDevice(LPTSTR lpszName, ULONG ulBatNum)
|
|
{
|
|
PBATTERY_STATE pbs, pbsTemp = &g_bs;
|
|
LPTSTR lpsz = NULL;
|
|
|
|
if (!lpszName) {
|
|
return NULL;
|
|
}
|
|
|
|
// Append to end of list
|
|
while (pbsTemp->bsNext) {
|
|
pbsTemp = pbsTemp->bsNext;
|
|
}
|
|
|
|
// Allocate storage for new battery device state.
|
|
if (pbs = LocalAlloc(LPTR, sizeof(BATTERY_STATE))) {
|
|
if (lpsz = LocalAlloc(0, STRSIZE(lpszName))) {
|
|
lstrcpy(lpsz, lpszName);
|
|
pbs->lpszDeviceName = lpsz;
|
|
pbs->ulSize = sizeof(BATTERY_STATE);
|
|
pbs->ulBatNum = ulBatNum;
|
|
|
|
// Open a handle to the battery driver.
|
|
pbs->hDevice = CreateFile(lpszName,
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL, OPEN_EXISTING,
|
|
FILE_ATTRIBUTE_NORMAL, NULL);
|
|
#ifdef WINNT
|
|
// Setup for notification by PNP when battery goes away.
|
|
RegisterForDeviceNotification(pbs);
|
|
#endif
|
|
// Get the current battery info from the battery driver.
|
|
if (UpdateBatInfoProc(pbs, NULL, 0, 0)) {
|
|
|
|
// Link the new battery device state into the list.
|
|
pbsTemp->bsNext = pbs;
|
|
pbs->bsPrev = pbsTemp;
|
|
return pbs;
|
|
}
|
|
LocalFree(lpsz);
|
|
}
|
|
LocalFree(pbs);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* SimAddBatteryStateDevice
|
|
*
|
|
* DESCRIPTION:
|
|
* Simulate the addition of displayable batteries to the battery list.
|
|
* New entry is appended to battery state list.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
PBATTERY_STATE SimAddBatteryStateDevice(LPTSTR lpszName, ULONG ulBatNum)
|
|
{
|
|
PBATTERY_STATE pbs, pbsTemp = &g_bs;
|
|
LPTSTR lpsz = NULL;
|
|
|
|
if (!lpszName) {
|
|
return NULL;
|
|
}
|
|
|
|
// Append to end of list
|
|
while (pbsTemp->bsNext) {
|
|
pbsTemp = pbsTemp->bsNext;
|
|
}
|
|
|
|
// Allocate storage for new battery device state.
|
|
if (pbs = LocalAlloc(LPTR, sizeof(BATTERY_STATE))) {
|
|
if (lpsz = LocalAlloc(0, STRSIZE(lpszName))) {
|
|
lstrcpy(lpsz, lpszName);
|
|
pbs->lpszDeviceName = lpsz;
|
|
pbs->ulSize = sizeof(BATTERY_STATE);
|
|
pbs->ulBatNum = ulBatNum;
|
|
|
|
// Open a handle to the battery driver.
|
|
pbs->hDevice = (HANDLE) -1;
|
|
|
|
// Get the current battery info from the battery driver.
|
|
if (SimUpdateBatInfoProc(pbs, NULL, 0, 0)) {
|
|
|
|
// Link the new battery device state into the list.
|
|
pbsTemp->bsNext = pbs;
|
|
pbs->bsPrev = pbsTemp;
|
|
return pbs;
|
|
}
|
|
LocalFree(lpsz);
|
|
}
|
|
LocalFree(pbs);
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RemoveBatteryStateDevice
|
|
*
|
|
* DESCRIPTION:
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL RemoveBatteryStateDevice(PBATTERY_STATE pbs)
|
|
{
|
|
// Unlink
|
|
if (pbs->bsNext) {
|
|
pbs->bsNext->bsPrev = pbs->bsPrev;
|
|
}
|
|
if (pbs->bsPrev) {
|
|
pbs->bsPrev->bsNext = pbs->bsNext;
|
|
}
|
|
|
|
#ifdef winnt
|
|
UnregisterForDeviceNotification(pbs);
|
|
#endif
|
|
|
|
// Free the battery driver handle if one was opened.
|
|
if (pbs->hDevice != INVALID_HANDLE_VALUE) {
|
|
CloseHandle(pbs->hDevice);
|
|
}
|
|
|
|
// Free the device name.
|
|
LocalFree(pbs->lpszDeviceName);
|
|
|
|
// Destroy any icons.
|
|
if (pbs->hIconCache) {
|
|
DestroyIcon(pbs->hIconCache);
|
|
}
|
|
if (pbs->hIconCache16) {
|
|
DestroyIcon(pbs->hIconCache16);
|
|
}
|
|
|
|
// Free the associated storage.
|
|
LocalFree(pbs);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* RemoveMissingProc
|
|
*
|
|
* DESCRIPTION:
|
|
* Remove a battery from the global battery state list.
|
|
*
|
|
* PARAMETERS:
|
|
* lParam2 - REMOVE_MISSING or REMOVE_ALL
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL RemoveMissingProc(
|
|
PBATTERY_STATE pbs,
|
|
HWND hWnd,
|
|
LPARAM lParam1,
|
|
LPARAM lParam2)
|
|
{
|
|
UINT i;
|
|
LPTSTR *pszDeviceNames;
|
|
|
|
if (lParam2 == REMOVE_MISSING) {
|
|
if ((pszDeviceNames = (LPTSTR *)lParam1) != NULL) {
|
|
for (i = 0; i < NUM_BAT; i++) {
|
|
if (pszDeviceNames[i]) {
|
|
if (!lstrcmp(pbs->lpszDeviceName, pszDeviceNames[i])) {
|
|
// Device found in device list, leave it alone.
|
|
return TRUE;
|
|
}
|
|
}
|
|
else {
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Device not in the device names list, remove it.
|
|
RemoveBatteryStateDevice(pbs);
|
|
return TRUE;
|
|
}
|
|
|
|
/*******************************************************************************
|
|
*
|
|
* FindNameProc
|
|
*
|
|
* DESCRIPTION:
|
|
* Returns FALSE (stop searching) if we find the name, else TRUE.
|
|
*
|
|
* PARAMETERS:
|
|
*
|
|
*******************************************************************************/
|
|
|
|
BOOL FindNameProc(PBATTERY_STATE pbs, HWND hWnd, LPARAM lParam1, LPARAM lParam2)
|
|
{
|
|
if (lParam1) {
|
|
if (!lstrcmp(pbs->lpszDeviceName, (LPTSTR)lParam1)) {
|
|
// Device found in device list.
|
|
return FALSE;
|
|
}
|
|
}
|
|
return TRUE;
|
|
}
|
|
|
|
|