This is article number 4 in a series of articles about monitoring batteries in Windows XP. So far, I have presented a C# class (Windows XP: Monitoring Batteries in C Sharp), a C++ class (Windows XP: Monitoring Batteries in C++) and a C# (Windows XP: Displaying Battery Status in C Sharp) application. In this article, I will present three different C++ applications:
1.       A console application
2.       A Win32 Dialog
3.       An MFC Dialog
Each application with use the C++ class used through a DLL. To keep things simple, they will use the C interface to the class.
A Console Application
The console application polls the battery status every second to get the battery status. When the app runs, it looks like:
 

The code is a simple:
#include "stdafx.h"
#include "WIN32Battery.h"
 
 
int _tmain(int argc, _TCHAR* argv[])
{
      HANDLE Batteries;
      int NumBatteries;
      SYSTEM_POWER_STATUS PowerStatus;
      char *PowerSource[] = {
            "Battery",
            "AC Power",
            "Unknown"
      };
 
      Batteries = InitWIN32_Battery();
 
      while( 1 )
      {
            WIN32_Battery_Refresh(Batteries);
 
            NumBatteries = WIN32_Battery_NumberOfBatteries(Batteries);
            printf( "\r\nNumber of batteries %d\r\n", NumBatteries );
            GetSystemPowerStatus(&PowerStatus);
            printf( "Running on %s\r\n", PowerSource[ PowerStatus.ACLineStatus ] );
 
            for( int BatteryNumber = 0; BatteryNumber < NumBatteries; BatteryNumber++ )
            {
                  int BatteryPercent;
                  BatteryPercent = WIN32_Battery_GetPercentChargeRemaining( Batteries, BatteryNumber );
                  printf( "Battery %d - %d%%\r\n", BatteryNumber, BatteryPercent );
            }
 
            Sleep( 1000 );
      }
 
      return 0;
}
 
This code initializes the Win32_Battery class by calling InitWIN32_Battery(), then loops getting the battery status by calling WIN32_Battery_Refresh() and WIN32_Battery_GetPercentChargeRemaining(). It determines if the system is running on battery or AC by calling GetSystemPowerStatsus().
The “trick” to this app, is to set up the linker to link with Win32Battery.lib so that the app can use Win32Battery.dll. Of course it could call LoadLibrary() and GetProcAddress(), but no need to do that when we have the lib available.
I was not able to find a way to get notifications when the battery status changes for a console application, nor did I spend a lot of time trying to find a way.
A Win32 Dialog
The Win32 Dialog looks similar to the C# application from the earlier article. First the dialog when running on AC with one battery:
And then running on battery with two batteries:
The biggest change is that it was much simpler to include a string field to show if the system is running on battery or AC than it was to do a checkbox, so I used a string.
To manage the dialog I created the following functions:
void HandleACPowerState(HWND hDlg)       
{    
      SYSTEM_POWER_STATUS PowerStatus;
     
      TCHAR *PowerSource[] =
      {
            L"Battery",
            L"AC Power",
            L"Unknown"
      };
      GetSystemPowerStatus(&PowerStatus);
      SetDlgItemText(hDlg,IDC_POWERSOURCE, PowerSource[ PowerStatus.ACLineStatus ]);
}
 
HandleACPowerState() sets the string field for battery or AC based on the results of calling GetSystemPowerStatus(), just like in the console app.
void Battery2ShowWindow(HWND hDlg, BOOL Show)
{
      HWND DlgItem;
      DlgItem = GetDlgItem(hDlg, IDC_BATTERY2LPERCENT );
      ShowWindow(DlgItem, Show );
      DlgItem = GetDlgItem(hDlg, IDC_BATTERY2LABEL );
      ShowWindow(DlgItem, Show );
      DlgItem = GetDlgItem(hDlg, IDC_BATTERY2GROUBBOX );
      ShowWindow(DlgItem, Show );
}
 
Battery2ShowWindow() hides or shows the second battery status as needed.
void SetBatteryPercent(HWND hDlg, HANDLE Batteries)
{
      TCHAR StPercent[10];
      int NumBatteries = WIN32_Battery_NumberOfBatteries(Batteries);
 
    if (NumBatteries > 0)
      {
            wsprintf( StPercent, L"%d%%", WIN32_Battery_GetPercentChargeRemaining(Batteries, 0));
            SetDlgItemText(hDlg,IDC_BATTERY1LPERCENT, StPercent);
      }
    else
      {
            SetDlgItemText(hDlg,IDC_BATTERY1LPERCENT, L"No Info Available");
      }
     
    if (NumBatteries > 1)
    {
            wsprintf( StPercent, L"%d%%", WIN32_Battery_GetPercentChargeRemaining(Batteries, 1));
            SetDlgItemText(hDlg,IDC_BATTERY2LPERCENT, StPercent);
            Battery2ShowWindow(hDlg, true);
    }
    else
    {
            Battery2ShowWindow(hDlg, false);
      }
}
SetBatteryPercent() uses WIN32_Battery_NumberOfBatteries() and WIN32_Battery_GetPercentChargeRemaining() to display the battery charge information.
To handle power notifications, I added the following to the windows messaging handling:
      case WM_POWERBROADCAST:
            {    
                  WIN32_Battery_Refresh(Batteries);
                  HandleACPowerState(hDlg);
                  SetBatteryPercent(hDlg, Batteries);
            }
            break;
 
The WM_POWERBROADCAST message is sent to all applications when the status of the batteries or AC power changes.
I chose to call WIN32_Battery_Refresh() here on the assumption that eventually I might add some other battery monitoring. WIN32_Battery_Refresh() is used to request a snapshot of the battery status.
An MFC Dialog
The MFC dialog looks more like the C# dialog because it includes the checkbox again. The dialog for running on AC with one battery looks like:
And the dialog with two batteries running on battery:
The code to manage the dialog display is:
void CCPP_BatteryMonitorDlg::Battery2ShowWindow(BOOL Show)
{
      CWnd *DlgItem = this->GetDlgItem(IDC_Battery2GroupBox);
      DlgItem->ShowWindow(Show);
      DlgItem = this->GetDlgItem(IDC_Battery2Label);
      DlgItem->ShowWindow(Show);
      DlgItem = this->GetDlgItem(IDC_Battery2Percent);
      DlgItem->ShowWindow(Show);
}
 
Just like the Win32 dialog, Battery2ShowWindow() shows or hides the second battery information as needed.
#define ON_BATTERY 0
 
void CCPP_BatteryMonitorDlg::SetBatteryPercent()
{
      TCHAR StPercent[10];
      int NumBatteries = WIN32_Battery_NumberOfBatteries(Batteries);
 
    if (NumBatteries > 0)
      {
            wsprintf( StPercent, L"%d%%", WIN32_Battery_GetPercentChargeRemaining(Batteries, 0));
            Battery1Percent = StPercent;
      }
    else
      {
            Battery1Percent = "No Info Available";
      }
    if (NumBatteries > 1)
    {
            wsprintf( StPercent, L"%d%%", WIN32_Battery_GetPercentChargeRemaining(Batteries, 1));
            Battery2Percent = StPercent;
            Battery2ShowWindow(true);
    }
    else
    {
            Battery2ShowWindow(false);
      }
}
 
Again, SetBatteryPercent() displays the current battery charge percent.
BOOL CCPP_BatteryMonitorDlg::IsOnBattery()
{
      SYSTEM_POWER_STATUS PowerStatus;
      GetSystemPowerStatus(&PowerStatus);
      return PowerStatus.ACLineStatus == ON_BATTERY;
}
 
For the MFC dialog, I added a function. IsOnBattery(), that returns true if the system is running on battery.
Finally, set up the app to handle the WM_POWERBROADCAST message.   This turns out to be more complicated with MFC, but when complete it is a little more elegant. First add a function to handle the message:
LRESULT CCPP_BatteryMonitorDlg::OnPowerChange(WPARAM, LPARAM)
{
      WIN32_Battery_Refresh(Batteries);
 
      this->CBOnBattery.SetCheck(IsOnBattery());
     
      SetBatteryPercent();
      this->UpdateData(0);
      return 1;
}
 
Just like how the Win32 dialog handled the message, this first calls WIN32_Battery_Refresh() and then updates the battery/AC checkbox and battery percents.
The next step is to add the message to the message map:
      ON_MESSAGE(WM_POWERBROADCAST, OnPowerChange )
 
And now we have three C++ applications that monitor and display battery information.
Copyright © 2010 – Bruce Eitman
All Rights Reserved