Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

809 lines
26 KiB

/*******************************************************************************
*
* (C) COPYRIGHT MICROSOFT CORP., 1993-1995
*
* TITLE: POWER.C
*
* VERSION: 2.0
*
* AUTHOR: TCS/RAL
*
* DATE: 08 Feb 1994
*
********************************************************************************
*
* CHANGE LOG:
*
* DATE REV DESCRIPTION
* ----------- --- -------------------------------------------------------------
* 08 Feb 1994 TCS Original implementation.
* 11 Nov 1994 RAL Converted from batmeter to systray
* 11 Aug 1995 JEM Split batmeter functions into power.c & minor enahncements
* 23 Oct 1995 Shawnb UNICODE Enabled
*
*******************************************************************************/
#include "systray.h"
#define BATTERY_STATUS_HIGH 0x00
#define BATTERY_STATUS_LOW 0x01
#define BATTERY_STATUS_CRITICAL 0x02
#define BATTERY_STATUS_CHARGING 0x03
// E X T E R N A L D A T A --------------------------------------------------
extern HANDLE g_hVpowerD; // Global handle to VPOWERD VxD
extern HINSTANCE g_hInstance; // Global instance handle 4 this application.
extern const TCHAR g_szRegstrPathSysTray[]; // Path to SysTray info
// G L O B A L D A T A -------------------------------------------------------
static DWORD g_dwBatFlags;
static DWORD g_dwPrevBatFlags;
static BOOL g_bPowerEnabled = FALSE;
static const TCHAR g_szRegstrValSysTrayBatFlags[] = REGSTR_VAL_SYSTRAYBATFLAGS;
#define BATFLAGS_LOWBATWARN (0x01) // low battery warning enabled flag
#define BATFLAGS_SHOWPERCENT (0x02) // always show battery life in %
// Flag indicating if low battery warning already given
static BYTE g_bGaveWarning = FALSE;
// Flag indicating that warning is already up-- there are cases when
// g_bGaveWarning will be reset to FALSE, but the message box will still be up.
static BYTE g_bShowingWarning = FALSE;
// g_bBatTimeKnow indicates if GetPowerStatus() returns remaining battery
// life in Time (in addition to percentage remaining).
static BOOL g_bBatTimeKnown = FALSE;
// Context sensitive help array used by the WinHelp engine.
const DWORD g_ContextMenuHelpIDs[] = {
IDC_POWERSTATUSGROUPBOX,IDH_POWERCFG_POWERSTATUSBAR,
IDC_POWERSTATUSICON, IDH_POWERCFG_POWERSTATUSBAR,
IDC_BATTERYLEVEL, IDH_POWERCFG_POWERSTATUSBAR,
IDC_REMAINING, IDH_POWERCFG_POWERSTATUSBAR,
IDC_POWERSTATUSBAR, IDH_POWERCFG_POWERSTATUSBAR,
IDC_LOWBATWARN, IDH_BATMETER_LOWBATWARN,
0, 0
};
// P R O T O T Y P E S -------------------------------------------------------
void PASCAL Power_UpdateStatus(HWND hWnd, DWORD NotifyIconMessage,
BOOL bForceUpdate);
BOOL PASCAL GetPowerStatus(HANDLE hVpowerD,
LPSYSTEM_POWER_STATUS lpSystemPowerStatus);
/*******************************************************************************
*
* GetPowerStatus
*
* DESCRIPTION:
* An internal replacement for the WIN32 GetSystemPowerStatus() API. Used to
* cut down on system overhead by eliminating CreatFile()/CloseHandle()
* calls.
*
* PARAMETERS:
* hVpowerD, handle to VPOWERD VxD
* lpSystemPowerStatus, pointer to SYSTEM_POWER_STATUS struct to fill in
*
*******************************************************************************/
BOOL PASCAL
GetPowerStatus (HANDLE hVpowerD, LPSYSTEM_POWER_STATUS lpSystemPowerStatus)
{
BOOL Result;
VPOWERD_W32_GET_SYSTEM_STATUS_PARAM W32GetSystemStatusParam;
W32GetSystemStatusParam.lpWin32SystemPowerStatus =
(LPWIN32_SYSTEM_POWER_STATUS) lpSystemPowerStatus;
if (!DeviceIoControl (hVpowerD, VPOWERD_IOCTL_W32_GET_SYSTEM_STATUS,
&W32GetSystemStatusParam, sizeof(VPOWERD_W32_GET_SYSTEM_STATUS_PARAM),
&Result, sizeof(Result), NULL, NULL))
Result = FALSE;
// If we fail to get the power status for whatever reason, fill in some
// correct values basically saying "we don't know!"
if (!Result)
{
lpSystemPowerStatus-> ACLineStatus = AC_LINE_UNKNOWN;
lpSystemPowerStatus-> BatteryFlag = BATTERY_FLAG_UNKNOWN;
lpSystemPowerStatus-> BatteryLifePercent = BATTERY_PERCENTAGE_UNKNOWN;
lpSystemPowerStatus-> BatteryLifeTime = BATTERY_LIFE_UNKNOWN;
lpSystemPowerStatus-> BatteryFullLifeTime = BATTERY_LIFE_UNKNOWN;
lpSystemPowerStatus-> Reserved1 = 0;
}
// Some APM BIOS implementations return an invalid value (0) for BatteryFlag.
// In this case we will set the BatteryFlag to Unknown.
if (lpSystemPowerStatus-> BatteryFlag == 0)
lpSystemPowerStatus-> BatteryFlag = BATTERY_FLAG_UNKNOWN;
return Result;
}
/*******************************************************************************
*
* Power_UpdateStatus
*
* DESCRIPTION:
*
* IMPORTANT: This code also is sitting in the power control panel applet.
* Any changes in this code will likely need to be reflected there as well.
*
* PARAMETERS:
* hWnd, handle of BatteryMeter window.
*
*******************************************************************************/
VOID
PASCAL
Power_UpdateStatus(
HWND hWnd,
DWORD NotifyIconMessage,
BOOL bForceUpdate
)
{
UINT NewIconID;
HICON hIcon;
LPTSTR pStr;
LPTSTR pBatteryLevelStr;
UINT BatteryLevelStringID=0;
UINT Counter;
DWORD BatteryLifeTime;
UINT Percent;
DWORD Hours;
DWORD Minutes;
BOOL fNewTip;
SYSTEM_POWER_STATUS SystemPowerStatus;
static UINT TrayIconID = 0; // ID of current tray icon
static HICON hTrayIcon = NULL;
static LPTSTR pLevelStr = NULL; // Battery level string
static LPTSTR pRemainStr = NULL; // Battery remaining life string
static UINT PowerSourceIconID = 0; // ID of current dialog icon
static HICON PowerSourceIcon = NULL;
static SYSTEM_POWER_STATUS LastPowerStatus;
static const struct {
BYTE nLowPercent; // if (% >= low &&
BYTE nHighPercent; // % <= high &&
BYTE wBatFlags; // flags match)
short nIconID; // use this icon
short nStrID; // and this string (if != 0)
} BatPolicy[] = {
{ 66, 100, BATTERY_FLAG_HIGH, IDI_FULLBATTERY, 0 },
{ 66, 100, BATTERY_FLAG_LOW, IDI_HALFBATTERY, 0 },
{ 34, 65, (BATTERY_FLAG_LOW | BATTERY_FLAG_HIGH), IDI_HALFBATTERY, 0 },
{ 0, 33, BATTERY_FLAG_HIGH, IDI_HALFBATTERY, 0 },
{ 11, 33, BATTERY_FLAG_LOW, IDI_ALMOSTDEADBATTERY, 0 },
{ 0, 10, BATTERY_FLAG_LOW, IDI_UTTERLYDEADBATTERY, 0 },
{ 0, 50, BATTERY_FLAG_CRITICAL, IDI_UTTERLYDEADBATTERY, 0 },
{ 51, 100, BATTERY_FLAG_CRITICAL, IDI_UNKNOWNBATTERY, IDS_UNKNOWN },
};
GetPowerStatus(g_hVpowerD, &SystemPowerStatus);
// Bail out early if nothing has changed since last time.
if (!bForceUpdate &&
SystemPowerStatus.ACLineStatus == LastPowerStatus.ACLineStatus &&
SystemPowerStatus.BatteryFlag == LastPowerStatus.BatteryFlag &&
SystemPowerStatus.BatteryLifeTime == LastPowerStatus.BatteryLifeTime &&
SystemPowerStatus.BatteryLifePercent == LastPowerStatus.BatteryLifePercent)
{
return;
}
LastPowerStatus = SystemPowerStatus; // Remember last status
// If we don't know the battery flag, map the battery life percentage to
// an approximate battery state.
if (SystemPowerStatus.BatteryFlag == BATTERY_FLAG_UNKNOWN &&
SystemPowerStatus.BatteryLifePercent != BATTERY_PERCENTAGE_UNKNOWN)
{
if (SystemPowerStatus.BatteryLifePercent >= 66)
SystemPowerStatus.BatteryFlag = BATTERY_FLAG_HIGH;
else if (SystemPowerStatus.BatteryLifePercent >= 33)
SystemPowerStatus.BatteryFlag = BATTERY_FLAG_LOW;
else
SystemPowerStatus.BatteryFlag = BATTERY_FLAG_CRITICAL;
}
// If we don't know the battery percentage, map the battery flag to an
// approximate percentage.
else
if (SystemPowerStatus.BatteryLifePercent == BATTERY_PERCENTAGE_UNKNOWN &&
SystemPowerStatus.BatteryFlag != BATTERY_FLAG_UNKNOWN)
{
if (SystemPowerStatus.BatteryFlag & BATTERY_FLAG_HIGH)
SystemPowerStatus.BatteryLifePercent = 100;
else if (SystemPowerStatus.BatteryFlag & BATTERY_FLAG_LOW)
SystemPowerStatus.BatteryLifePercent = 33;
else if (SystemPowerStatus.BatteryFlag & BATTERY_FLAG_CRITICAL)
SystemPowerStatus.BatteryLifePercent = 10;
}
// Display the amount of time remaining preferably in the number of hours,
// otherwise as a percentage. Last resort is to say we just don't know!
if (((g_dwBatFlags & BATFLAGS_SHOWPERCENT) == 0) &&
SystemPowerStatus.BatteryLifeTime != BATTERY_LIFE_UNKNOWN)
{
BatteryLifeTime = (UINT) (SystemPowerStatus.BatteryLifeTime / 60);
Hours = BatteryLifeTime / 60;
Minutes = BatteryLifeTime % 60;
if (Hours > 0)
pStr = LoadDynamicString(IDS_TIMEREMAININGFORMAT, Hours, Minutes / 6);
else
pStr = LoadDynamicString(IDS_SMTIMEREMAININGFORMAT, Minutes);
}
else if (SystemPowerStatus.BatteryLifePercent <= 100)
pStr = LoadDynamicString(IDS_PERCENTREMAININGFORMAT,
(DWORD)SystemPowerStatus.BatteryLifePercent);
else
pStr = LoadDynamicString(IDS_REMAININGUNKNOWN);
// Update the battery life remaining string if changed. The remaining life
// string is also the battery meter's tooltip msg.
if (fNewTip = (pRemainStr == NULL || lstrcmp(pRemainStr, pStr) != 0))
{
if (pRemainStr != NULL)
DeleteDynamicString(pRemainStr);
SetDlgItemText(hWnd, IDC_REMAINING, pStr);
pRemainStr = pStr;
}
else
DeleteDynamicString(pStr);
// Pick which battery icon to display in the tray
NewIconID = IDI_UNKNOWNBATTERY;
if (SystemPowerStatus.ACLineStatus == AC_LINE_ONLINE)
NewIconID = IDI_ACPOWER;
else
if (SystemPowerStatus.BatteryFlag != BATTERY_FLAG_UNKNOWN &&
!(SystemPowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY))
{
int i;
// Match current state against policy table to pick battery icon
for (i = 0; i < (ARRAYSIZE(BatPolicy)); i++)
if (SystemPowerStatus.BatteryLifePercent >= BatPolicy[i].nLowPercent &&
SystemPowerStatus.BatteryLifePercent <= BatPolicy[i].nHighPercent &&
(SystemPowerStatus.BatteryFlag & BatPolicy[i].wBatFlags))
{
NewIconID = BatPolicy[i].nIconID;
if (BatPolicy[i].nStrID != 0)
BatteryLevelStringID = BatPolicy[i].nStrID;
break;
}
}
// Pick the Battery level string to display in the dialog box
if (BatteryLevelStringID != IDS_UNKNOWN)
{
BatteryLevelStringID = IDS_UNKNOWN;
if (SystemPowerStatus.BatteryFlag != BATTERY_FLAG_UNKNOWN)
{
if (SystemPowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY)
BatteryLevelStringID = IDS_NO_BATTERY;
else
for (Counter = BATTERY_STATUS_HIGH; Counter <=
BATTERY_STATUS_CHARGING; Counter++)
if (SystemPowerStatus.BatteryFlag & (1 << Counter))
{
BatteryLevelStringID = IDS_HIGH + Counter;
break;
}
}
}
// If AC is on-line, display either Charging or AC On-Line
if (SystemPowerStatus.ACLineStatus == AC_LINE_ONLINE &&
BatteryLevelStringID != IDS_CHARGING)
pStr = LoadDynamicString(IDS_ACLINEONLINE);
else
{
pStr = pBatteryLevelStr = LoadDynamicString(BatteryLevelStringID);
if (BatteryLevelStringID != IDS_NO_BATTERY)
{
pStr = LoadDynamicString(IDS_BATTERYLEVELFORMAT,(LPTSTR)pBatteryLevelStr);
DeleteDynamicString(pBatteryLevelStr);
}
}
// Update the battery level text if changed
if (pLevelStr == NULL || lstrcmp(pLevelStr, pStr) != 0)
{
if (pLevelStr != NULL)
DeleteDynamicString(pLevelStr);
SetDlgItemText(hWnd, IDC_BATTERYLEVEL, pStr);
pLevelStr = pStr;
}
else
DeleteDynamicString(pStr);
// Update the tray if the icon or tip msg has changed
if (TrayIconID != NewIconID || fNewTip)
{
hIcon = (TrayIconID != NewIconID) ?
LoadImage(g_hInstance, MAKEINTRESOURCE(NewIconID),
IMAGE_ICON, 16, 16, 0) : hTrayIcon;
SysTray_NotifyIcon(hWnd, STWM_NOTIFYPOWER, NotifyIconMessage,
hIcon, pRemainStr);
if (hTrayIcon != NULL && hTrayIcon != hIcon)
DestroyIcon(hTrayIcon);
TrayIconID = NewIconID;
hTrayIcon = hIcon;
}
// Pick the icon to display in the dialog box
if (SystemPowerStatus.ACLineStatus == AC_LINE_ONLINE ||
BatteryLevelStringID == IDS_CHARGING)
NewIconID = IDI_ACPOWER;
if (PowerSourceIconID != NewIconID)
{
hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(NewIconID));
SendDlgItemMessage(hWnd, IDC_POWERSTATUSICON, STM_SETICON, (WPARAM) hIcon, 0);
if (PowerSourceIcon)
DestroyIcon(PowerSourceIcon);
PowerSourceIconID = NewIconID;
PowerSourceIcon = hIcon;
}
// Update the power status bar which graphically displays the battery
// percentage.
if (SystemPowerStatus.BatteryLifePercent <= 100)
Percent = SystemPowerStatus.BatteryLifePercent;
else
Percent = 0;
SendDlgItemMessage(hWnd, IDC_POWERSTATUSBAR, PBM_SETPOS, (WPARAM) Percent, 0);
// If the user wants low battery warnings, show the warning msg box if the
// battery level just went low.
if ((g_dwBatFlags & BATFLAGS_LOWBATWARN) &&
SystemPowerStatus.BatteryFlag != BATTERY_FLAG_UNKNOWN &&
SystemPowerStatus.ACLineStatus != AC_LINE_ONLINE)
{
// low is (flag_critical && % <= 50) or (flag_low && % <= 10)
if ((SystemPowerStatus.BatteryFlag & BATTERY_FLAG_LOW &&
SystemPowerStatus.BatteryLifePercent <= 10) ||
(SystemPowerStatus.BatteryFlag & BATTERY_FLAG_CRITICAL &&
SystemPowerStatus.BatteryLifePercent <= 50))
{
if (!g_bGaveWarning && !g_bShowingWarning)
// only do this once per transition to low
{
MSGBOXPARAMS MsgBoxParams;
g_bGaveWarning = TRUE;
MsgBoxParams.cbSize = sizeof(MSGBOXPARAMS);
MsgBoxParams.hwndOwner = NULL;
MsgBoxParams.hInstance = g_hInstance;
MsgBoxParams.lpszText = MAKEINTRESOURCE(IDS_LOWBAT_MSG);
MsgBoxParams.lpszCaption = MAKEINTRESOURCE(IDS_LOWBAT_TITLE);
MsgBoxParams.dwStyle = MB_OK | MB_SETFOREGROUND | MB_USERICON;
MsgBoxParams.lpszIcon = MAKEINTRESOURCE(IDI_ALMOSTDEADBATTERY);
MsgBoxParams.dwContextHelpId = 0;
MsgBoxParams.lpfnMsgBoxCallback = 0;
MsgBoxParams.dwLanguageId = 0;
g_bShowingWarning = TRUE;
MessageBoxIndirect(&MsgBoxParams);
g_bShowingWarning = FALSE;
}
}
else
g_bGaveWarning = FALSE; // reset if battery is no longer low
}
else
g_bGaveWarning = FALSE; // reset if we transition AC line states
}
/*----------------------------------------------------------------------------
* Power_OnCommand
*
* Process WM_COMMAND msgs for the battery meter dialog.
*
*----------------------------------------------------------------------------*/
void
Power_OnCommand(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
switch (GET_WM_COMMAND_ID(wParam, lParam)) {
case IDOK:
// Save low battery warning flag if changed
Power_UpdateFlags(BATFLAGS_LOWBATWARN,
IsDlgButtonChecked(hWnd, IDC_LOWBATWARN));
g_bGaveWarning = FALSE;
/* fall through */
case IDCANCEL:
ShowWindow(hWnd, SW_HIDE);
break;
}
}
/*----------------------------------------------------------------------------
* GetPowerMenu()
*
* Build a menu containing battery meter/power selections. There are two
* menus, one for the left mouse button, and one for the right mouse button.
*
*----------------------------------------------------------------------------*/
#define POWERMENU_OPEN 100
#define POWERMENU_PROPERTIES 101
#define POWERMENU_ENABLEWARN 200
#define POWERMENU_SHOWTIME 201
#define POWERMENU_SHOWPERCENT 202
static HMENU _hMenu[2] = {0};
static HMENU
GetPowerMenu(LONG l)
{
HMENU hMenu;
LPTSTR lpszMenu;
if (l > 0)
{
// Right button menu -- never changes, only build itt the first time.
if (_hMenu[1] == NULL)
{
hMenu = _hMenu[l] = CreatePopupMenu();
// Open
if ((lpszMenu = LoadDynamicString(IDS_OPEN)) != NULL)
{
AppendMenu(hMenu, MF_STRING, POWERMENU_OPEN, lpszMenu);
DeleteDynamicString(lpszMenu);
}
// Properties for Power...
if ((lpszMenu = LoadDynamicString(IDS_PROPFORPOWER)) != NULL)
{
AppendMenu(hMenu, MF_STRING, POWERMENU_PROPERTIES, lpszMenu);
DeleteDynamicString(lpszMenu);
}
// Open is default (double click action)
SetMenuDefaultItem(hMenu, POWERMENU_OPEN, FALSE);
}
}
else
{
// Left button menu -- can change, rebuild each time.
if (_hMenu[0])
{
DestroyMenu(_hMenu[0]);
}
hMenu = _hMenu[0] = CreatePopupMenu();
// Enable low battery warning
if ((lpszMenu = LoadDynamicString(IDS_ENABLELOWBATWARN)) != NULL)
{
AppendMenu(hMenu,MF_STRING, POWERMENU_ENABLEWARN, lpszMenu);
DeleteDynamicString(lpszMenu);
}
if (g_dwBatFlags & BATFLAGS_LOWBATWARN)
CheckMenuItem(hMenu, POWERMENU_ENABLEWARN, MF_BYCOMMAND | MF_CHECKED);
// Show battery life in time OR
// Show battery life in percent
if (g_bBatTimeKnown) // is time available?
{
// Flip between offering "show time" and "show percent"
BOOL bTime = ((g_dwBatFlags & BATFLAGS_SHOWPERCENT) != 0);
if ((lpszMenu = LoadDynamicString(bTime ? IDS_SHOWBATTIME :
IDS_SHOWBATPERCENT)) != NULL)
{
AppendMenu(hMenu, MF_STRING, bTime ? POWERMENU_SHOWTIME :
POWERMENU_SHOWPERCENT, lpszMenu);
DeleteDynamicString(lpszMenu);
}
}
}
return _hMenu[l];
}
/*----------------------------------------------------------------------------
* Power_Open
*
* Update and display the battery meter dialog
*
*----------------------------------------------------------------------------*/
static void
Power_Open(HWND hWnd)
{
Power_UpdateStatus(hWnd, NIM_MODIFY, FALSE); // show current info
ShowWindow(hWnd, SW_SHOW);
SetForegroundWindow(hWnd);
}
/*----------------------------------------------------------------------------
* DoPowerMenu
*
* Create and process a right or left button menu.
*
*----------------------------------------------------------------------------*/
static void
DoPowerMenu(HWND hwnd, UINT uMenuNum, UINT uButton)
{
POINT pt;
UINT iCmd;
SetForegroundWindow(hwnd);
GetCursorPos(&pt);
iCmd = TrackPopupMenu(GetPowerMenu(uMenuNum), uButton | TPM_RETURNCMD | TPM_NONOTIFY,
pt.x, pt.y, 0, hwnd, NULL);
switch (iCmd)
{
case POWERMENU_OPEN:
Power_Open(hwnd);
break;
case POWERMENU_PROPERTIES:
SysTray_RunProperties(IDS_RUNPOWERPROPERTIES);
break;
case POWERMENU_ENABLEWARN:
Power_UpdateFlags(BATFLAGS_LOWBATWARN,
((g_dwBatFlags & BATFLAGS_LOWBATWARN) == 0));
CheckDlgButton(hwnd, IDC_LOWBATWARN, (g_dwBatFlags & BATFLAGS_LOWBATWARN) != 0);
break;
case POWERMENU_SHOWTIME:
case POWERMENU_SHOWPERCENT:
Power_UpdateFlags(BATFLAGS_SHOWPERCENT,
(iCmd == POWERMENU_SHOWPERCENT));
Power_UpdateStatus(hwnd, NIM_MODIFY, TRUE);
break;
}
}
/*----------------------------------------------------------------------------
* Power_Notify
*
* Handle a notification from the power tray icon.
*
*----------------------------------------------------------------------------*/
void Power_Notify(HWND hWnd, WPARAM wParam, LPARAM lParam)
{
switch (lParam)
{
case WM_RBUTTONUP:
DoPowerMenu(hWnd, 1, TPM_RIGHTBUTTON); // right button menu
break;
case WM_LBUTTONDOWN:
// start timing for left button menu
SetTimer(hWnd, POWER_TIMER_ID, GetDoubleClickTime()+100, NULL);
break;
case WM_LBUTTONDBLCLK:
KillTimer(hWnd, POWER_TIMER_ID); // cancel left button menu
Power_Open(hWnd); // show battery meter dialog
break;
}
}
/*----------------------------------------------------------------------------
* Power_Timer
*
* Execute the left button menu on WM_LBUTTONDOWN time-out.
*
*----------------------------------------------------------------------------*/
void Power_Timer(HWND hwnd)
{
KillTimer(hwnd, POWER_TIMER_ID);
DoPowerMenu(hwnd, 0, TPM_LEFTBUTTON);
}
/*----------------------------------------------------------------------------
* Power_UpdateFlags
*
* Update power flags under SysTray registry key.
*
*----------------------------------------------------------------------------*/
void
Power_UpdateFlags(DWORD dwMask, BOOL bEnable)
{
HKEY hk;
if (bEnable)
g_dwBatFlags |= dwMask;
else
g_dwBatFlags &= ~dwMask;
if (g_dwBatFlags != g_dwPrevBatFlags &&
RegOpenKey(HKEY_CURRENT_USER, g_szRegstrPathSysTray, &hk) == ERROR_SUCCESS)
{
GenericGetSet(hk, g_szRegstrValSysTrayBatFlags, &g_dwBatFlags,
sizeof(g_dwBatFlags), TRUE);
g_dwPrevBatFlags = g_dwBatFlags;
}
}
/*******************************************************************************
*
* BatteryMeterInit(hWnd)
*
* DESCRIPTION:
* NOTE: Can be called multiple times. Simply re-init.
*
* PARAMETERS:
* (returns), TRUE if the Battery Meter could be enabled
*
*******************************************************************************/
BOOL
PASCAL
BatteryMeterInit(HWND hWnd)
{
BOOL Result;
DWORD Version;
SYSTEM_POWER_STATUS SystemPowerStatus;
SendDlgItemMessage(hWnd, IDC_POWERSTATUSBAR, PBM_SETRANGE, 0,
MAKELPARAM(0,100));
// Check for the existence of VPOWERD and validate that we have at least
// version 4.0 of this device (which it had better be if it's allowing
// a DeviceIoControl!).
if (g_hVpowerD == INVALID_HANDLE_VALUE) {
g_hVpowerD = CreateFile(TEXT ("\\\\.\\VPOWERD"), GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
if (g_hVpowerD == INVALID_HANDLE_VALUE) {
return FALSE;
}
Result = DeviceIoControl(g_hVpowerD, VPOWERD_IOCTL_GET_VERSION, NULL, 0,
&Version, sizeof(DWORD), NULL, NULL);
if (Result == FALSE || Version < 0x0400)
return FALSE;
}
// Check if this system actually has a battery -- don't run if not.
// Also, if no battery, remove the Registry RUN line for BatteryMeter
// since it always gets added when Windows is installed on an APM machine.
//
// Assume there is no battery if the GetPowerStatus() call fails.
// Some desktop APM implementations (no system battery) fail this call.
// Also, if the BIOS is returns Unknown for both AC line status
// and BatteryFlag (example: NEC 1.1 BIOS) don't show Batmeter.
// If it fails once it will most likely always fail.
if (GetPowerStatus(g_hVpowerD, &SystemPowerStatus) == FALSE ||
( (SystemPowerStatus.BatteryFlag != BATTERY_FLAG_UNKNOWN &&
SystemPowerStatus.BatteryFlag & BATTERY_FLAG_NO_BATTERY) ||
(SystemPowerStatus.ACLineStatus == AC_LINE_UNKNOWN &&
SystemPowerStatus.BatteryFlag == BATTERY_FLAG_UNKNOWN) ))
{
return FALSE;
}
// Set global flag if GetPowerStatus() returned something for remaining
// battery life in time
g_bBatTimeKnown = (SystemPowerStatus.BatteryLifeTime != BATTERY_LIFE_UNKNOWN);
return TRUE;
}
/*******************************************************************************
*
* Power_CheckEnable
*
* DESCRIPTION:
* NOTE: Can be called multiple times. Simply re-init.
*
* PARAMETERS:
* bSvcEnabled is TRUE if the user has enabled power meter on tray
* (returns), TRUE if the Battery Meter could be enabled
*
*******************************************************************************/
BOOL Power_CheckEnable(HWND hWnd, BOOL bSvcEnabled)
{
HKEY hk;
BOOL bEnable = bSvcEnabled && BatteryMeterInit(hWnd);
if (bEnable != g_bPowerEnabled) {
g_bPowerEnabled = bEnable;
if (bEnable) {
#ifdef DEBUG
MessageBox(hWnd, TEXT ("Enabling battery meter"), TEXT ("SYSTRAY"), MB_OK | MB_ICONEXCLAMATION);
#endif
// Get current low battery warning on/off flag -- default to on
if (RegOpenKey(HKEY_CURRENT_USER, g_szRegstrPathSysTray, &hk) != ERROR_SUCCESS ||
GenericGetSet(hk, g_szRegstrValSysTrayBatFlags, &g_dwBatFlags,
sizeof(g_dwBatFlags), FALSE) == FALSE)
g_dwBatFlags = BATFLAGS_LOWBATWARN;
g_dwPrevBatFlags = g_dwBatFlags;
CheckDlgButton(hWnd, IDC_LOWBATWARN, (g_dwBatFlags & BATFLAGS_LOWBATWARN) != 0);
Power_UpdateStatus(hWnd, NIM_ADD, FALSE);
SetTimer(hWnd, PWRSTATUS_UPDATE_TIMER_ID,
PWRSTATUS_UPDATE_TIMER_TIMEOUT, NULL);
} else {
#ifdef DEBUG
MessageBox(hWnd, TEXT ("Disabling battery meter"), TEXT ("SYSTRAY"), MB_OK | MB_ICONEXCLAMATION);
#endif
KillTimer(hWnd, PWRSTATUS_UPDATE_TIMER_ID);
SysTray_NotifyIcon(hWnd, STWM_NOTIFYPOWER, NIM_DELETE, NULL, NULL);
CloseIfOpen(&g_hVpowerD);
}
}
return(bEnable);
}