|
|
/*******************************************************************************
* * (C) COPYRIGHT MICROSOFT CORP., 1997 * * TITLE: BATMETER.C * * VERSION: 2.0 * * AUTHOR: ReedB * * DATE: 17 Oct, 1996 * * DESCRIPTION: * * Implements the battery meter of the PowerCfg or SysTray battery * meter windows. The battery meter has two display modes, single and * multi-battery. In single mode, a representation of the total of all battery * capacity in a system is displayed. In multi-battery mode, battery * information is displayed for each individual battery as well as the total. * * The battery meter parent window receives notification from USER when * any battery status has changed through the WM_POWERBROADCAST, * PBT_APMPOWERSTATUSCHANGE message. * * ??? We need to add perfmon support: Create and maintain keys/values * under HKEY_PERFORMANCE_DATA. * *******************************************************************************/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#include <windows.h>
#include <commctrl.h>
#include <dbt.h>
#include <objbase.h>
#include <initguid.h>
#include <ntpoapi.h>
#include <poclass.h>
#include <setupapi.h>
#include <syssetup.h>
#include <setupbat.h>
#include <ccstock.h>
#include <help.h>
#include "powrprofp.h"
#include "batmeter.h"
#include "bmresid.h"
#include "..\powercfg\PwrMn_cs.h"
#include "shfusion.h"
// Simulated battery only for debug build.
#ifndef DEBUG
#undef SIM_BATTERY
#endif
// Define some things for debug.h. Required when you include ccstock.h in
// one and only one file.
#define SZ_DEBUGINI "ccshell.ini"
#define SZ_DEBUGSECTION "BATMETER"
#define SZ_MODULE "BATMETER"
#define DECLARE_DEBUG
#include <debug.h>
/*******************************************************************************
* * G L O B A L D A T A * *******************************************************************************/
HINSTANCE g_hInstance; // Global instance handle of this DLL.
HWND g_hwndParent; // Parent of the battery meter.
HWND g_hwndBatMeter; // Battery meter.
// The following constant global array is used to walk through the
// control ID's in the battery metter dialog box. It makes getting
// a control ID from a battery number easy.
#define BAT_ICON 0
#define BAT_STATUS 1
#define BAT_REMAINING 2
#define BAT_NUM 3
#define BAT_LAST BAT_NUM+1
UINT g_iMapBatNumToID [NUM_BAT+1][4]={ {IDC_POWERSTATUSICON, IDC_POWERSTATUSBAR, IDC_REMAINING, IDC_BATNUM0}, {IDC_POWERSTATUSICON1, IDC_STATUS1, IDC_REMAINING1, IDC_BATNUM1}, {IDC_POWERSTATUSICON2, IDC_STATUS2, IDC_REMAINING2, IDC_BATNUM2}, {IDC_POWERSTATUSICON3, IDC_STATUS3, IDC_REMAINING3, IDC_BATNUM3}, {IDC_POWERSTATUSICON4, IDC_STATUS4, IDC_REMAINING4, IDC_BATNUM4}, {IDC_POWERSTATUSICON5, IDC_STATUS5, IDC_REMAINING5, IDC_BATNUM5}, {IDC_POWERSTATUSICON6, IDC_STATUS6, IDC_REMAINING6, IDC_BATNUM6}, {IDC_POWERSTATUSICON7, IDC_STATUS7, IDC_REMAINING7, IDC_BATNUM7}, {IDC_POWERSTATUSICON8, IDC_STATUS8, IDC_REMAINING8, IDC_BATNUM8} };
// 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_uiBatCount is the count of
// battery devices in this list. The composite battery is not counted. The
// g_pbs array provides a handy UI battery number to pbs conversion. The
// following three variables are only changed during DeviceChanged.
BATTERY_STATE g_bs; UINT g_uiBatCount; PBATTERY_STATE g_pbs[NUM_BAT+1]; LPTSTR g_lpszDriverNames[NUM_BAT]; UINT g_uiDriverCount; BOOL g_bShowingMulti;
// The following array provides context sensitive help associations between
// resource control identifiers and help resource string identifiers.
const DWORD g_ContextMenuHelpIDs[] = { IDC_BATMETERGROUPBOX, IDH_COMM_GROUPBOX, IDC_BATMETERGROUPBOX1, IDH_COMM_GROUPBOX, IDC_POWERSTATUSICON, NO_HELP, IDC_POWERSTATUSICON1, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON2, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON3, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON4, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON5, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON6, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON7, IDH_BATMETER_CHARGING_ICON, IDC_POWERSTATUSICON8, IDH_BATMETER_CHARGING_ICON, IDC_BATNUM1, NO_HELP, IDC_BATNUM2, NO_HELP, IDC_BATNUM3, NO_HELP, IDC_BATNUM4, NO_HELP, IDC_BATNUM5, NO_HELP, IDC_BATNUM6, NO_HELP, IDC_BATNUM7, NO_HELP, IDC_BATNUM8, NO_HELP, IDC_STATUS1, NO_HELP, IDC_STATUS2, NO_HELP, IDC_STATUS3, NO_HELP, IDC_STATUS4, NO_HELP, IDC_STATUS5, NO_HELP, IDC_STATUS6, NO_HELP, IDC_STATUS7, NO_HELP, IDC_STATUS8, NO_HELP, IDC_MOREINFO, NO_HELP, IDC_CURRENTPOWERSOURCE, IDH_BATMETER_CURPOWERSOURCE, IDC_BATTERYLEVEL, IDH_BATMETER_CURPOWERSOURCE, IDC_TOTALBATPWRREMAINING, IDH_BATMETER_TOTALBATPOWER, IDC_REMAINING, IDH_BATMETER_TOTALBATPOWER, IDC_POWERSTATUSBAR, IDH_BATMETER_TOTALBATPOWER, IDC_BARPERCENT, IDH_BATMETER_TOTALBATPOWER, IDC_TOTALTIME, IDH_BATMETER_TOTALTIME, IDC_TIMEREMAINING, IDH_BATMETER_TOTALTIME, IDC_BATTERYNAME, IDH_DETAILED_BATINFO_LABELS, IDC_DEVNAME, IDH_DETAILED_BATINFO_LABELS, IDC_UNIQUEID, IDH_DETAILED_BATINFO_LABELS, IDC_BATID, IDH_DETAILED_BATINFO_LABELS, IDC_MANUFACTURE, IDH_DETAILED_BATINFO_LABELS, IDC_BATMANNAME, IDH_DETAILED_BATINFO_LABELS, IDC_DATEMANUFACTURED, IDH_DETAILED_BATINFO_LABELS, IDC_BATMANDATE, IDH_DETAILED_BATINFO_LABELS, IDC_CHEMISTRY, IDH_DETAILED_BATINFO_LABELS, IDC_CHEM, IDH_DETAILED_BATINFO_LABELS, IDC_POWERSTATE, IDH_DETAILED_BATINFO_LABELS, IDC_STATE, IDH_DETAILED_BATINFO_LABELS, IDC_REFRESH, IDH_DETAILED_BATINFO_REFRESH, 0, 0 };
/*******************************************************************************
* * P U B L I C E N T R Y P O I N T S * *******************************************************************************/
/*******************************************************************************
* * DllInitialize * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
BOOL DllInitialize(IN PVOID hmod, IN ULONG ulReason, IN PCONTEXT pctx OPTIONAL) { UNREFERENCED_PARAMETER(pctx);
switch (ulReason) {
case DLL_PROCESS_ATTACH: g_hInstance = hmod; DisableThreadLibraryCalls(g_hInstance); SHFusionInitializeFromModuleID(hmod, 124); break;
case DLL_PROCESS_DETACH: SHFusionUninitialize(); break; } return TRUE; }
/*******************************************************************************
* * PowerCapabilities * * DESCRIPTION: * This public function is used to determine if the system has any power * management capabilities which require UI support. Return TRUE if power * management UI should be displayed. * * PARAMETERS: * *******************************************************************************/
BOOL PowerCapabilities() { SYSTEM_POWER_CAPABILITIES spc; int dummy;
#ifndef SIM_BATTERY
if (GetPwrCapabilities(&spc)) { if ((spc.PowerButtonPresent) || (spc.SleepButtonPresent) || (spc.LidPresent) || (spc.SystemS1) || (spc.SystemS2) || (spc.SystemS3) || (spc.SystemS4) || (spc.SystemS5) || (spc.DiskSpinDown) || (spc.SystemBatteriesPresent)) { return TRUE; } else { if (SystemParametersInfo(SPI_GETLOWPOWERACTIVE, 0, &dummy, 0)) { return TRUE; } } } return FALSE; #else
return TRUE; #endif
}
/*******************************************************************************
* * BatMeterCapabilities * * DESCRIPTION: * This public function is used to determine if the battery meter library * can run on the host machine. Return TRUE on success (battery meter can run). * * PARAMETERS: * ppuiBatCount - Points to a pointer which will be filled in with a pointer * to the global battery count. * *******************************************************************************/
BOOL BatMeterCapabilities( PUINT *ppuiBatCount ) { #ifndef SIM_BATTERY
SYSTEM_POWER_CAPABILITIES spc; #endif // SIM_BATTERY
if (ppuiBatCount) { *ppuiBatCount = &g_uiBatCount; } g_uiBatCount = 0;
#ifndef SIM_BATTERY
// Make sure we have batteries to query.
if (GetPwrCapabilities(&spc)) { if (spc.SystemBatteriesPresent) { g_uiDriverCount = GetBatteryDriverNames(g_lpszDriverNames); if (g_uiDriverCount != 0) { g_uiBatCount = g_uiDriverCount;
return TRUE; } else { BATTRACE(( "BatMeterCapabilities, no battery drivers found.")); } } } return FALSE;
#else // SIM_BATTERY
g_uiBatCount = g_uiDriverCount = GetBatteryDriverNames(g_lpszDriverNames); return UpdateDriverList(g_lpszDriverNames, g_uiDriverCount); #endif // SIM_BATTERY
}
/*******************************************************************************
* * CreateBatMeter * * DESCRIPTION: * Create, fetch data for and draw the battery meter window. Returns a handle * to the newly created battery meter window on success, NULL on failure. * * PARAMETERS: * hwndParent - Parent of the battery meter dialog. * wndFrame - Frame to locate the battery meter dialog. * bShowMulti - Specifies the display mode (TRUE -> multiple battery). * pbsComposite - Optional pointer to composite battery state. * *******************************************************************************/
HWND CreateBatMeter( HWND hwndParent, HWND hwndFrame, BOOL bShowMulti, PBATTERY_STATE pbsComposite ) { INT iWidth, iHeight; RECT rFrame = {0};
// Build the battery devices name list if hasn't already been built.
if (!g_uiBatCount) { BatMeterCapabilities(NULL); }
// Remember if we are showing details for each battery
g_bShowingMulti = bShowMulti;
// Make sure we have at least one battery.
if (g_uiBatCount) { // Create the battery meter control.
g_hwndParent = hwndParent; g_hwndBatMeter = CreateDialog(g_hInstance, MAKEINTRESOURCE(IDD_BATMETER), hwndParent, BatMeterDlgProc);
// Place the battery meter in the passed frame window.
if ((g_hwndBatMeter) && (hwndFrame)) { // Position the BatMeter dialog in the frame.
if (!GetWindowRect(hwndFrame, &rFrame)) { BATTRACE(( "CreateBatMeter, GetWindowRect failed, hwndFrame: %08X", hwndFrame)); }
iWidth = rFrame.right - rFrame.left; iHeight = rFrame.bottom - rFrame.top;
if (IsBiDiLocalizedSystemEx(NULL)) { // Whistler #209400: On BIDI systems, ScreenToClient() wants the right
// coord in the left location because everything is flipped.
rFrame.left = rFrame.right; }
if (!ScreenToClient(hwndParent, (LPPOINT)&rFrame)) { BATTRACE(( "CreateBatMeter, ScreenToClient failed")); }
if (!MoveWindow(g_hwndBatMeter, rFrame.left, rFrame.top, iWidth, iHeight, FALSE)) { BATTRACE(( "CreateBatMeter, MoveWindow failed, %d, %d", rFrame.left, rFrame.top)); }
// Build the battery driver data list.
if (!UpdateDriverList(g_lpszDriverNames, g_uiDriverCount)) { return DestroyBatMeter(g_hwndBatMeter); }
// Do the first update.
UpdateBatMeter(g_hwndBatMeter, bShowMulti, TRUE, pbsComposite); ShowWindow(g_hwndBatMeter, SW_SHOWNOACTIVATE); } }
return g_hwndBatMeter; }
/*******************************************************************************
* * DestroyBatMeter * * DESCRIPTION: * *******************************************************************************/
HWND DestroyBatMeter(HWND hWnd) { SendMessage(hWnd, WM_DESTROYBATMETER, 0, 0); g_hwndBatMeter = NULL; return g_hwndBatMeter; }
/*******************************************************************************
* * UpdateBatMeter * * DESCRIPTION: * This function should be called when the battery meter parent window * receives a WM_POWERBROADCAST, PBT_APMPOWERSTATUSCHANGE message, it will * update the data in the global battery state list. If needed the display * will also be updated. * * PARAMETERS: * HWND hwndBatMeter, hWnd of the battery meter dialog * BOOL bShowMulti, Specifies the display mode * BOOL bForceUpdate, Forces a UI update * PBATTERY_STATE pbsComposite Optional pointer to composite battery state. * *******************************************************************************/
BOOL UpdateBatMeter( HWND hWnd, BOOL bShowMulti, BOOL bForceUpdate, PBATTERY_STATE pbsComposite ) { BOOL bRet = FALSE; SYSTEM_POWER_STATUS sps; UINT uIconID;
// Update the composite battery state.
if (GetSystemPowerStatus(&sps) && hWnd) { if (sps.BatteryLifePercent > 100) { BATTRACE(( "GetSystemPowerStatuse, set BatteryLifePercent: %d", sps.BatteryLifePercent)); }
// Fill in the composite battery state.
SystemPowerStatusToBatteryState(&sps, &g_bs);
// Update the information in the battery state list if we have a battery.
if (g_hwndBatMeter) {
#ifndef SIM_BATTERY
WalkBatteryState(DEVICES, (WALKENUMPROC)UpdateBatInfoProc, NULL, (LPARAM)NULL, (LPARAM)NULL); #else
WalkBatteryState(DEVICES, (WALKENUMPROC)SimUpdateBatInfoProc, NULL, (LPARAM)NULL, (LPARAM)NULL); #endif
// See if the current display mode matches the requested mode.
if ((g_bShowingMulti != bShowMulti) || (bForceUpdate)) { g_bShowingMulti = SwitchDisplayMode(hWnd, bShowMulti); bForceUpdate = TRUE; }
if (g_bShowingMulti) { // Walk the bs list, and update all battery displays.
WalkBatteryState(ALL, (WALKENUMPROC)UpdateBatMeterProc, hWnd, (LPARAM)g_bShowingMulti, (LPARAM)bForceUpdate); } else { // Display only the comosite battery information.
UpdateBatMeterProc(&g_bs, hWnd, (LPARAM)g_bShowingMulti, (LPARAM)bForceUpdate); } bRet = TRUE; } } else { // Fill in default composite info.
g_bs.ulPowerState = BATTERY_POWER_ON_LINE; g_bs.ulBatLifePercent = (UINT) -1; g_bs.ulBatLifeTime = (UINT) -1;
uIconID = MapBatInfoToIconID(&g_bs); g_bs.hIconCache = GetBattIcon(hWnd, uIconID, g_bs.hIconCache, FALSE, 32); g_bs.hIconCache16 = GetBattIcon(hWnd, uIconID, g_bs.hIconCache16, FALSE, 16); }
// If a pointer is provided, copy the composite battery state data.
if (pbsComposite) { if (pbsComposite->ulSize == sizeof(BATTERY_STATE)) { memcpy(pbsComposite, &g_bs, sizeof(BATTERY_STATE)); } else { BATTRACE(( "UpdateBatMeter, passed BATTERY_STATE size is invalid")); } } return bRet; }
/*******************************************************************************
* * P R I V A T E F U N C T I O N S * *******************************************************************************/
/*******************************************************************************
* * LoadDynamicString * * DESCRIPTION: * Wrapper for the FormatMessage function that loads a string from our * resource table into a dynamically allocated buffer, optionally filling * it with the variable arguments passed. * * PARAMETERS: * uiStringID - resource identifier of the string to use. * ... - Optional parameters to use to format the string message. * *******************************************************************************/
LPTSTR CDECL LoadDynamicString(UINT uiStringID, ... ) { va_list Marker; TCHAR szBuf[256]; LPTSTR lpsz; int iLen;
// va_start is a macro...it breaks when you use it as an assign...on ALPHA.
va_start(Marker, uiStringID);
iLen = LoadString(g_hInstance, uiStringID, szBuf, ARRAYSIZE(szBuf));
if (iLen == 0) { BATTRACE(( "LoadDynamicString: LoadString on: 0x%X failed", uiStringID)); return NULL; }
FormatMessage(FORMAT_MESSAGE_FROM_STRING | FORMAT_MESSAGE_ALLOCATE_BUFFER, (LPVOID) szBuf, 0, 0, (LPTSTR)&lpsz, 0, &Marker);
return lpsz; }
/*******************************************************************************
* * DisplayFreeStr * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
LPTSTR DisplayFreeStr(HWND hWnd, UINT uID, LPTSTR lpsz, BOOL bFree) { if (lpsz) { SetDlgItemText(hWnd, uID, lpsz); ShowWindow(GetDlgItem(hWnd, uID), SW_SHOWNOACTIVATE); if (bFree) { LocalFree(lpsz); return NULL; } } else { ShowWindow(GetDlgItem(hWnd, uID), SW_HIDE); } return lpsz; }
/*******************************************************************************
* * ShowHideItem * ShowItem * HideItem * * DESCRIPTION: * Handy helpers to show or hide dialog items in the battery meter dialog. * * PARAMETERS: * hWnd - Battery meter dialog handle. * uID - Control ID of control to be shown or hidden. * *******************************************************************************/
BOOL ShowHideItem(HWND hWnd, UINT uID, BOOL bShow) { ShowWindow(GetDlgItem(hWnd, uID), (bShow) ? SW_SHOWNOACTIVATE : SW_HIDE); return bShow; }
void ShowItem(HWND hWnd, UINT uID) { ShowWindow(GetDlgItem(hWnd, uID), SW_SHOWNOACTIVATE); }
void HideItem(HWND hWnd, UINT uID) { ShowWindow(GetDlgItem(hWnd, uID), SW_HIDE); }
/*******************************************************************************
* * SwitchDisplayMode * * DESCRIPTION: * Return TRUE if display is switched to multi battery mode. * * PARAMETERS: * *******************************************************************************/
BOOL SwitchDisplayMode(HWND hWnd, BOOL bShowMulti) { ULONG i, j;
// Override request if multi-battery display is not possible.
if ((bShowMulti) && (!g_uiBatCount)) { bShowMulti = FALSE; }
if (!g_uiBatCount) {
//
// Hide all info if no batteries are installed
//
HideItem(hWnd, IDC_POWERSTATUSBAR); HideItem(hWnd, IDC_BARPERCENT); HideItem(hWnd, IDC_MOREINFO);
} else if (bShowMulti) { HideItem(hWnd, IDC_POWERSTATUSBAR); HideItem(hWnd, IDC_BARPERCENT); ShowItem(hWnd, IDC_MOREINFO);
for (i = 1; i <= g_uiBatCount; i++) { for (j = 0; j < BAT_LAST; j++) { ShowItem(hWnd, g_iMapBatNumToID[i][0]); } } } else { for (i = 1; i <= g_uiBatCount; i++) { for (j = 0; j < BAT_LAST; j++) { HideItem(hWnd, g_iMapBatNumToID[i][j]); } }
ShowItem(hWnd, IDC_POWERSTATUSBAR); ShowItem(hWnd, IDC_BARPERCENT); HideItem(hWnd, IDC_MOREINFO); } return bShowMulti; }
/*******************************************************************************
* * CleanupBatteryData * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
void CleanupBatteryData(void) { g_hwndBatMeter = NULL;
// Mark all batteries as missing.
memset(&g_pbs, 0, sizeof(g_pbs));
// Walk the bs list, remove all devices and cleanup.
WalkBatteryState(DEVICES, (WALKENUMPROC)RemoveMissingProc, NULL, (LPARAM)NULL, (LPARAM)REMOVE_ALL);
// Free any old driver names.
FreeBatteryDriverNames(g_lpszDriverNames); g_uiBatCount = 0; }
/*******************************************************************************
* * BatMeterDlgProc * * DESCRIPTION: * DialogProc for the Battery Meter control. Provide support for more battery * info. * * PARAMETERS: * *******************************************************************************/
LRESULT CALLBACK BatMeterDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { #ifdef WINNT
UINT i, j; PBATTERY_STATE pbsTemp; #endif // WINNT
UINT uiBatNum;
switch (uMsg) { case WM_COMMAND: if ((HIWORD(wParam) == STN_CLICKED) || (HIWORD(wParam) == BN_CLICKED)) { switch (LOWORD(wParam)) { case IDC_POWERSTATUSICON1: case IDC_POWERSTATUSICON2: case IDC_POWERSTATUSICON3: case IDC_POWERSTATUSICON4: case IDC_POWERSTATUSICON5: case IDC_POWERSTATUSICON6: case IDC_POWERSTATUSICON7: case IDC_POWERSTATUSICON8: uiBatNum = LOWORD(wParam) - IDC_POWERSTATUSICON1 + 1; // Allow battery details only for present batteries.
if ((g_pbs[uiBatNum]) && (g_pbs[uiBatNum]->ulTag != BATTERY_TAG_INVALID)) { DialogBoxParam(g_hInstance, MAKEINTRESOURCE(IDD_BATDETAIL), hWnd, BatDetailDlgProc, (LPARAM)g_pbs[uiBatNum]); } break; } } break;
case WM_DESTROYBATMETER: CleanupBatteryData(); EndDialog(hWnd, wParam); break;
case WM_DESTROY: CleanupBatteryData(); break;
case WM_DEVICECHANGE: #ifdef WINNT
if ((wParam == DBT_DEVICEQUERYREMOVE) || (wParam == DBT_DEVICEREMOVECOMPLETE)) { if ( ((PDEV_BROADCAST_HANDLE)lParam)->dbch_devicetype == DBT_DEVTYP_HANDLE) {
//
// Find Device that got removed
//
pbsTemp = DEVICES; while (pbsTemp) { if (pbsTemp->hDevNotify == ((PDEV_BROADCAST_HANDLE)lParam)->dbch_hdevnotify) { break; } pbsTemp = pbsTemp->bsNext; } if (!pbsTemp) { break; }
//
// Close the handle to this device and release cached data.
//
RemoveBatteryStateDevice (pbsTemp); g_uiDriverCount--; g_uiBatCount = g_uiDriverCount;
// Clear and rebuild g_pbs, the handy batttery number to pbs array.
memset(&g_pbs, 0, sizeof(g_pbs)); pbsTemp = &g_bs; for (i = 0; i <= g_uiBatCount; i++) { if (pbsTemp) { g_pbs[i] = pbsTemp; pbsTemp->ulBatNum = i; pbsTemp = pbsTemp->bsNext; } }
// Refresh display
for (i = 1; i <= NUM_BAT; i++) { for (j = 0; j < BAT_LAST; j++) { HideItem(g_hwndBatMeter, g_iMapBatNumToID[i][j]); } }
g_bShowingMulti = SwitchDisplayMode (g_hwndBatMeter, g_bShowingMulti); if (g_bShowingMulti) { // Walk the bs list, and update all battery displays.
WalkBatteryState(DEVICES, (WALKENUMPROC)UpdateBatMeterProc, g_hwndBatMeter, (LPARAM)g_bShowingMulti, (LPARAM)TRUE); } } } #else
if (wParam == DBT_DEVICEQUERYREMOVE) { if (g_hwndBatMeter) { // Close all of the batteries.
CleanupBatteryData(); } } #endif
return TRUE;
case WM_HELP: // F1
WinHelp(((LPHELPINFO)lParam)->hItemHandle, PWRMANHLP, HELP_WM_HELP, (ULONG_PTR)(LPTSTR)g_ContextMenuHelpIDs); return TRUE;
case WM_CONTEXTMENU: // right mouse click
WinHelp((HWND)wParam, PWRMANHLP, HELP_CONTEXTMENU, (ULONG_PTR)(LPTSTR)g_ContextMenuHelpIDs); return TRUE; } return FALSE; }
/*******************************************************************************
* * GetBattIcon * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
HICON PASCAL GetBattIcon( HWND hWnd, UINT uIconID, HICON hIconCache, BOOL bWantBolt, UINT uiRes) { static HIMAGELIST hImgLst32, hImgLst16; HIMAGELIST hImgLst; int ImageIndex;
// Destroy the old cached icon.
if (hIconCache) { DestroyIcon(hIconCache); }
// Don't put the charging bolt over the top of IDI_BATGONE.
if (uIconID == IDI_BATGONE) { bWantBolt = FALSE; }
// Use the transparency color must match that in the bit maps.
if (!hImgLst32 || !hImgLst16) { hImgLst32 = ImageList_LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_BATTS), 32, 0, RGB(255, 0, 255), IMAGE_BITMAP, 0); hImgLst16 = ImageList_LoadImage(g_hInstance, MAKEINTRESOURCE(IDB_BATTS16), 16, 0, RGB(255, 0, 255), IMAGE_BITMAP, 0); ImageList_SetOverlayImage(hImgLst32, IDI_CHARGE-FIRST_ICON_IMAGE, 1); ImageList_SetOverlayImage(hImgLst16, IDI_CHARGE-FIRST_ICON_IMAGE, 1); }
if (uiRes == 32) { hImgLst = hImgLst32; } else { hImgLst = hImgLst16; }
ImageIndex = uIconID - FIRST_ICON_IMAGE;
if (bWantBolt) { return ImageList_GetIcon(hImgLst, ImageIndex, INDEXTOOVERLAYMASK(1)); } else { return ImageList_GetIcon(hImgLst, ImageIndex, ILD_NORMAL); } }
/*******************************************************************************
* * CheckUpdateBatteryState * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
#define UPDATESTATUS_NOUPDATE 0
#define UPDATESTATUS_UPDATE 1
#define UPDATESTATUS_UPDATE_CHARGE 2
UINT CheckUpdateBatteryState( PBATTERY_STATE pbs, BOOL bForceUpdate ) { UINT uiRetVal = UPDATESTATUS_NOUPDATE;
// Check to see if anything in the battery status has changed
// since last time. If not then we have no work to do!
if ((bForceUpdate) || !((pbs->ulTag == pbs->ulLastTag) && (pbs->ulBatLifePercent == pbs->ulLastBatLifePercent) && (pbs->ulBatLifeTime == pbs->ulLastBatLifeTime) && (pbs->ulPowerState == pbs->ulLastPowerState))) {
uiRetVal = UPDATESTATUS_UPDATE;
// Check for the special case where the charging state has changed.
if ((pbs->ulPowerState & BATTERY_CHARGING) != (pbs->ulLastPowerState & BATTERY_CHARGING)) { uiRetVal |= UPDATESTATUS_UPDATE_CHARGE; }
// Copy current battery state to last.
pbs->ulLastTag = pbs->ulTag; pbs->ulLastBatLifePercent = pbs->ulBatLifePercent; pbs->ulLastBatLifeTime = pbs->ulBatLifeTime; pbs->ulLastPowerState = pbs->ulPowerState; } return uiRetVal; }
/*******************************************************************************
* * MapBatInfoToIconID * * DESCRIPTION: * Map battery info to an Icon ID. * * PARAMETERS: * ulBatNum - Zero implies composite system state * *******************************************************************************/
UINT MapBatInfoToIconID(PBATTERY_STATE pbs) { UINT uIconID = IDI_BATDEAD;
if (!pbs->ulBatNum) { if (pbs->ulPowerState & BATTERY_POWER_ON_LINE) { return IDI_PLUG; } } else { if (pbs->ulTag == BATTERY_TAG_INVALID) { return IDI_BATGONE; } }
if (pbs->ulPowerState & BATTERY_CRITICAL) { return IDI_BATDEAD; }
if (pbs->ulBatLifePercent > 66) { uIconID = IDI_BATFULL; } else { if (pbs->ulBatLifePercent > 33) { uIconID = IDI_BATHALF; } else { if (pbs->ulBatLifePercent > 9) { uIconID = IDI_BATLOW; } } }
return uIconID; }
/*******************************************************************************
* * DisplayIcon * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
void DisplayIcon( HWND hWnd, UINT uIconID, PBATTERY_STATE pbs, ULONG ulUpdateStatus ) { BOOL bBolt; UINT uiMsg;
// Only redraw the icon if it has changed OR
// if it has gone from charging to not charging.
if ((uIconID != pbs->uiIconIDcache) || (ulUpdateStatus != UPDATESTATUS_NOUPDATE)) {
pbs->uiIconIDcache = uIconID; bBolt = (pbs->ulPowerState & BATTERY_CHARGING);
pbs->hIconCache = GetBattIcon(hWnd, uIconID, pbs->hIconCache, bBolt, 32); pbs->hIconCache16 = GetBattIcon(hWnd, uIconID, pbs->hIconCache16, bBolt, 16);
if (pbs->ulBatNum) { uiMsg = BM_SETIMAGE; } else { uiMsg = STM_SETIMAGE; } SendDlgItemMessage(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_ICON], uiMsg, IMAGE_ICON, (LPARAM) pbs->hIconCache); ShowItem(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_ICON]); } }
/*******************************************************************************
* * UpdateBatMeterProc * * DESCRIPTION: * Updates the System and per battery UI elements if needed. * * PARAMETERS: * *******************************************************************************/
BOOL UpdateBatMeterProc( PBATTERY_STATE pbs, HWND hWnd, LPARAM bShowMulti, LPARAM bForceUpdate ) { UINT uIconID, uiHour, uiMin; LPTSTR lpsz, lpszRemaining; ULONG ulUpdateStatus;
ulUpdateStatus = CheckUpdateBatteryState(pbs, (BOOL) bForceUpdate);
// Make sure there is work to do.
if (ulUpdateStatus == UPDATESTATUS_NOUPDATE) { return TRUE; }
// Determine which icon to display.
uIconID = MapBatInfoToIconID(pbs); DisplayIcon(hWnd, uIconID, pbs, ulUpdateStatus);
// Are we looking for system power status ?
if (!pbs->ulBatNum) {
// Display the Current Power Source text
lpsz = LoadDynamicString(((pbs->ulPowerState & BATTERY_POWER_ON_LINE) ? IDS_ACLINEONLINE : IDS_BATTERIES)); DisplayFreeStr(hWnd, IDC_BATTERYLEVEL, lpsz, FREE_STR);
if (pbs->ulBatLifePercent <= 100) { lpsz = LoadDynamicString(IDS_PERCENTREMAININGFORMAT, pbs->ulBatLifePercent); } else { lpsz = LoadDynamicString(IDS_UNKNOWN); } DisplayFreeStr(hWnd, IDC_REMAINING, lpsz, NO_FREE_STR);
ShowHideItem(hWnd, IDC_CHARGING, pbs->ulPowerState & BATTERY_CHARGING);
// Show and Update the PowerStatusBar only if in single battery mode and
// there is al least one battery installed.
if (!bShowMulti && g_uiBatCount) { SendDlgItemMessage(hWnd, IDC_POWERSTATUSBAR, PBM_SETPOS, (WPARAM) pbs->ulBatLifePercent, 0); lpsz = DisplayFreeStr(hWnd, IDC_BARPERCENT, lpsz, FREE_STR); }
if (lpsz) { LocalFree(lpsz); }
if (pbs->ulBatLifeTime != (UINT) -1) { uiHour = pbs->ulBatLifeTime / 3600; uiMin = (pbs->ulBatLifeTime % 3600) / 60; if (uiHour) { lpsz = LoadDynamicString(IDS_TIMEREMFORMATHOUR, uiHour, uiMin); } else { lpsz = LoadDynamicString(IDS_TIMEREMFORMATMIN, uiMin); } DisplayFreeStr(hWnd, IDC_TIMEREMAINING, lpsz, FREE_STR); ShowHideItem(hWnd, IDC_TOTALTIME, TRUE); } else { ShowHideItem(hWnd, IDC_TOTALTIME, FALSE); ShowHideItem(hWnd, IDC_TIMEREMAINING, FALSE); } } else {
// Here when getting the power status of each individual battery
// when in multi-battery display mode.
lpsz = LoadDynamicString(IDS_BATNUM, pbs->ulBatNum); DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_NUM], lpsz, FREE_STR);
if (pbs->ulTag != BATTERY_TAG_INVALID) { if (pbs->ulPowerState & BATTERY_CHARGING) { lpsz = LoadDynamicString(IDS_BATTCHARGING); } else { lpsz = NULL; } lpszRemaining = LoadDynamicString(IDS_PERCENTREMAININGFORMAT, pbs->ulBatLifePercent); } else { lpsz = LoadDynamicString(IDS_NOT_PRESENT); lpszRemaining = NULL; } DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_STATUS], lpsz, FREE_STR);
DisplayFreeStr(hWnd, g_iMapBatNumToID[pbs->ulBatNum][BAT_REMAINING], lpszRemaining, FREE_STR); } return TRUE; }
/*******************************************************************************
* * FreeBatteryDriverNames * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
VOID FreeBatteryDriverNames(LPTSTR *lpszDriverNames) { UINT i;
// Free any old driver names.
for (i = 0; i < NUM_BAT; i++) { if (lpszDriverNames[i]) { LocalFree(lpszDriverNames[i]); lpszDriverNames[i] = NULL; } } }
/*******************************************************************************
* * GetBatteryDriverNames * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
UINT GetBatteryDriverNames(LPTSTR *lpszDriverNames) { UINT uiDriverCount, uiIndex; DWORD dwReqSize; HDEVINFO hDevInfo; SP_INTERFACE_DEVICE_DATA InterfaceDevData; PSP_INTERFACE_DEVICE_DETAIL_DATA pFuncClassDevData;
// Free any old driver names.
FreeBatteryDriverNames(lpszDriverNames); uiDriverCount = 0;
#ifndef SIM_BATTERY
// Use the SETUPAPI.DLL interface to get the
// possible battery driver names.
hDevInfo = SetupDiGetClassDevs((LPGUID)&GUID_DEVICE_BATTERY, NULL, NULL, DIGCF_PRESENT | DIGCF_INTERFACEDEVICE);
if (hDevInfo != INVALID_HANDLE_VALUE) { InterfaceDevData.cbSize = sizeof(SP_DEVINFO_DATA);
uiIndex = 0; while (uiDriverCount < NUM_BAT) { if (SetupDiEnumInterfaceDevice(hDevInfo, 0, (LPGUID)&GUID_DEVICE_BATTERY, uiIndex, &InterfaceDevData)) {
// Get the required size of the function class device data.
SetupDiGetInterfaceDeviceDetail(hDevInfo, &InterfaceDevData, NULL, 0, &dwReqSize, NULL);
pFuncClassDevData = LocalAlloc(0, dwReqSize); if (pFuncClassDevData != NULL) { pFuncClassDevData->cbSize = sizeof(SP_INTERFACE_DEVICE_DETAIL_DATA);
if (SetupDiGetInterfaceDeviceDetail(hDevInfo, &InterfaceDevData, pFuncClassDevData, dwReqSize, &dwReqSize, NULL)) {
dwReqSize = (lstrlen(pFuncClassDevData->DevicePath) + 1) * sizeof(TCHAR); lpszDriverNames[uiDriverCount] = LocalAlloc(0, dwReqSize);
if (lpszDriverNames[uiDriverCount]) { lstrcpyn(lpszDriverNames[uiDriverCount], pFuncClassDevData->DevicePath, dwReqSize); uiDriverCount++; } } else { BATTRACE(("SetupDiGetInterfaceDeviceDetail, failed: %d", GetLastError())); }
LocalFree(pFuncClassDevData); } } else { if (ERROR_NO_MORE_ITEMS == GetLastError()) { break; } else { BATTRACE(("SetupDiEnumInterfaceDevice, failed: %d", GetLastError())); } } uiIndex++; } SetupDiDestroyDeviceInfoList(hDevInfo); } else { BATTRACE(("SetupDiGetClassDevs on GUID_DEVICE_BATTERY, failed: %d", GetLastError())); } #else
// Simulate batteries.
{ UINT i; static UINT uiState = 1;
uiDriverCount = 0; for (i = 0; i <= uiState; i++) { lpszDriverNames[i] = LocalAlloc(0, STRSIZE(TEXT("SIMULATED_BATTERY_0"))); if (lpszDriverNames[i]) { wsprintf(lpszDriverNames[i], TEXT("SIMULATED_BATTERY_%d"), i); uiDriverCount += 1; } } uiState++; if (uiState >= NUM_BAT) { uiState = 0; } } #endif
return uiDriverCount; }
/*******************************************************************************
* * UpdateDriverList * * DESCRIPTION: * * PARAMETERS: * *******************************************************************************/
BOOL UpdateDriverList( LPTSTR *lpszDriverNames, UINT uiDriverCount ) { UINT i; PBATTERY_STATE pbs;
// Walk the bs list, and remove any devices which aren't in pszDeviceNames.
WalkBatteryState(DEVICES, (WALKENUMPROC)RemoveMissingProc, NULL, (LPARAM)g_lpszDriverNames, (LPARAM)REMOVE_MISSING);
// Scan the pszDeviceNames list and add any devices which aren't in bs.
for (i = 0; i < uiDriverCount; i++) {
if (WalkBatteryState(DEVICES, (WALKENUMPROC)FindNameProc, NULL, (LPARAM)g_lpszDriverNames[i], (LPARAM)NULL)) {
#ifndef SIM_BATTERY
if (!AddBatteryStateDevice(g_lpszDriverNames[i], i + 1)) { // We weren't able get minimal info from driver, dec the
// battery counts. g_uiBatCount should always be > 0.
if (--g_uiDriverCount) {; g_uiBatCount--; } } #else
SimAddBatteryStateDevice(g_lpszDriverNames[i], i + 1); #endif
} }
// Clear and rebuild g_pbs, the handy batttery number to pbs array.
memset(&g_pbs, 0, sizeof(g_pbs)); pbs = &g_bs; for (i = 0; i <= g_uiBatCount; i++) { if (pbs) { g_pbs[i] = pbs; pbs = pbs->bsNext; } } return TRUE; }
|