Click here to Skip to main content
15,881,882 members
Articles / Desktop Programming / WTL

Vista Goodies in C++: Monitoring the Computer's Power Status

Rate me:
Please Sign up or sign in to vote.
5.00/5 (18 votes)
29 Dec 20067 min read 105.9K   2.5K   44  
How to use power status notifications to make your applications conserve power when necessary.
// MainDlg.cpp : implementation of the CMainDlg class
/////////////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "resource.h"
#include "aboutdlg.h"
#include "MainDlg.h"

/////////////////////////////////////////////////////////////////////////////

static COLORREF GetRandomColor()
{
    return RGB(rand() & 0xFF, rand() & 0xFF, rand() & 0xFF);
}


/////////////////////////////////////////////////////////////////////////////
// Construction

CMainDlg::CMainDlg() :
    m_bOnBattery(false), m_nBatteryPower(100), m_eCurrPowerScheme(pwrBalanced),
    m_hPowerSchemeNotify(NULL), m_hPowerSourceNotify(NULL),
    m_hBatteryPowerNotify(NULL), m_bUseAnimation(true)
{
    SetThemeClassList ( L"globals" );
}


/////////////////////////////////////////////////////////////////////////////
// Message/command handlers

BOOL CMainDlg::PreTranslateMessage(MSG* pMsg)
{
    return CWindow::IsDialogMessage(pMsg);
}

BOOL CMainDlg::OnInitDialog ( HWND hwndFocus, LPARAM lParam )
{
    // Register for notifications about the power status.
    m_hPowerSchemeNotify = RegisterPowerSettingNotification ( m_hWnd, &GUID_POWERSCHEME_PERSONALITY, DEVICE_NOTIFY_WINDOW_HANDLE );

    if ( NULL == m_hPowerSchemeNotify )
        ATLTRACE("Failed to register for notification of power scheme changes!\n");

    m_hPowerSourceNotify = RegisterPowerSettingNotification ( m_hWnd, &GUID_ACDC_POWER_SOURCE, DEVICE_NOTIFY_WINDOW_HANDLE );

    if ( NULL == m_hPowerSourceNotify )
        ATLTRACE("Failed to register for notification of power source changes!\n");

    m_hBatteryPowerNotify = RegisterPowerSettingNotification ( m_hWnd, &GUID_BATTERY_PERCENTAGE_REMAINING, DEVICE_NOTIFY_WINDOW_HANDLE );

    if ( NULL == m_hBatteryPowerNotify )
        ATLTRACE("Failed to register for notification of battery power changes!\n");

    // Set up controls & stuff
    DoDataExchange();
    EnableThemeDialogTexture ( ETDT_ENABLE );
    srand ( GetTickCount() );
    m_cMessage.ModifyStyle ( SS_TYPEMASK, SS_OWNERDRAW );

    // center the dialog on the screen
    CenterWindow();

    // set icons
HICON hIcon = AtlLoadIcon ( IDR_MAINFRAME );
HICON hIconSmall = AtlLoadIconImage ( IDR_MAINFRAME, LR_DEFAULTCOLOR, 16, 16 );

    SetIcon(hIcon, TRUE);
    SetIcon(hIconSmall, FALSE);

    // register object for message filtering and idle updates
CMessageLoop* pLoop = _Module.GetMessageLoop();

    ATLASSERT(pLoop != NULL);
    pLoop->AddMessageFilter(this);

    // Start a timer to repaint the message area every second
    SetTimer ( 1, 1000 );

    return TRUE;
}

void CMainDlg::OnTimer ( UINT uID, TIMERPROC pProc )
{
    if ( 1 != uID )
        {
        SetMsgHandled(false);
        return;
        }

    if ( m_bUseAnimation )
        m_cMessage.RedrawWindow();
}

void CMainDlg::OnAppAbout ( UINT uCode, int nID, HWND hwndCtrl )
{
CAboutDlg dlg;

    dlg.DoModal();
}

void CMainDlg::OnCancel ( UINT uCode, int nID, HWND hwndCtrl )
{
    KillTimer(1);

    if ( NULL != m_hPowerSchemeNotify )
        UnregisterPowerSettingNotification ( m_hPowerSchemeNotify );

    if ( NULL != m_hPowerSourceNotify )
        UnregisterPowerSettingNotification ( m_hPowerSourceNotify );

    if ( NULL != m_hBatteryPowerNotify )
        UnregisterPowerSettingNotification ( m_hBatteryPowerNotify );

    DestroyWindow();
    PostQuitMessage ( nID );
}

LRESULT CMainDlg::OnPowerBroadcast ( DWORD dwEvent, DWORD dwData )
{
    // We only care about Vista power setting notifications.
    if ( PBT_POWERSETTINGCHANGE != dwEvent )
        {
        SetMsgHandled(false);
        return 0;
        }

POWERBROADCAST_SETTING* pps = (POWERBROADCAST_SETTING*) dwData;

    if ( sizeof(GUID) == pps->DataLength &&
         pps->PowerSetting == GUID_POWERSCHEME_PERSONALITY )
        {
        // This is a power scheme change notification
        GUID newScheme = *(GUID*)(DWORD_PTR) pps->Data;

        if ( GUID_MAX_POWER_SAVINGS == newScheme )
            {
            // New scheme: max power savings
            m_eCurrPowerScheme = pwrPowerSaver;

            m_cPowerScheme.SetWindowText ( _T("Power saver") );
            }
        else if ( GUID_MIN_POWER_SAVINGS == newScheme )
            {
            // New scheme: min power savings (max perf)
            m_eCurrPowerScheme = pwrMaxPerf;

            m_cPowerScheme.SetWindowText ( _T("Max performance") );
            }
        else if ( GUID_TYPICAL_POWER_SAVINGS == newScheme )
            {
            // New scheme: balanced
            m_eCurrPowerScheme = pwrBalanced;

            m_cPowerScheme.SetWindowText ( _T("Balanced") );
            }
        else
            {
            // Unrecognized scheme, we'll treat this like balanced
            m_eCurrPowerScheme = pwrBalanced;

            m_cPowerScheme.SetWindowText ( _T("Balanced") );
            }
        }
    else if ( sizeof(int) == pps->DataLength &&
              pps->PowerSetting == GUID_ACDC_POWER_SOURCE )
        {
        // This is a power source change notification
        int nPowerSrc = *(int*)(DWORD_PTR) pps->Data;

        m_bOnBattery = (0 != nPowerSrc);

        m_cPowerSource.SetWindowText ( m_bOnBattery ? _T("Battery") : _T("AC power") );
        }
    else if ( sizeof(int) == pps->DataLength &&
              pps->PowerSetting == GUID_BATTERY_PERCENTAGE_REMAINING )
        {
        // This is a battery power notification
        int nPercentLeft = *(int*)(DWORD_PTR) pps->Data;
        CString sPercentLeft;

        sPercentLeft.Format ( _T("%d"), nPercentLeft );
        m_cBatteryPower.SetWindowText ( sPercentLeft );
        m_nBatteryPower = nPercentLeft;
        }

    // Use animation in either of these cases:
    // 1. The current scheme is max perf
    // 2. The current scheme is balanced and the computer is not running on batteries
    // However, don't use animation if the computer is on batteries and the
    // battery power is <= 20%, regardless of the current scheme.
bool bUseAnimation = (pwrMaxPerf == m_eCurrPowerScheme) ||
                     (pwrBalanced == m_eCurrPowerScheme && !m_bOnBattery);

    if ( m_bOnBattery && m_nBatteryPower <= 20 )
        bUseAnimation = false;

    // If the animation setting has changed, save the new setting and redraw
    // the message area.
    if ( bUseAnimation != m_bUseAnimation )
        {
        m_bUseAnimation = bUseAnimation;
        m_cMessage.RedrawWindow();
        }

    return TRUE;    // allow all power actions
}

void CMainDlg::OnDrawItem ( UINT uID, LPDRAWITEMSTRUCT lpdis )
{
CDCHandle dc = lpdis->hDC;
CRect rcCtrl = lpdis->rcItem;
CString sText;
const UINT uFormat = DT_SINGLELINE|DT_CENTER|DT_VCENTER|DT_NOPREFIX;

    if ( IDC_MESSAGE != uID || ODT_STATIC != lpdis->CtlType )
        {
        SetMsgHandled(false);
        return;
        }

    m_cMessage.GetWindowText ( sText );
    dc.SaveDC();

    if ( m_bUseAnimation )
        {
        dc.FillSolidRect ( rcCtrl, GetRandomColor() );
        dc.SetTextColor ( GetRandomColor() );
        dc.SetBkColor ( GetRandomColor() );
        dc.SetBkMode ( OPAQUE );
        }
    else
        {
        dc.FillSolidRect ( rcCtrl, GetSysColor(COLOR_3DFACE) );
        dc.SetBkMode ( TRANSPARENT );
        dc.SetTextColor ( GetSysColor(COLOR_WINDOWTEXT) );
        }

    dc.SelectFont ( GetFont() );
    dc.DrawText ( sText, -1, rcCtrl, uFormat );
    dc.RestoreDC(-1);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Software Developer (Senior) VMware
United States United States
Michael lives in sunny Mountain View, California. He started programming with an Apple //e in 4th grade, graduated from UCLA with a math degree in 1994, and immediately landed a job as a QA engineer at Symantec, working on the Norton AntiVirus team. He pretty much taught himself Windows and MFC programming, and in 1999 he designed and coded a new interface for Norton AntiVirus 2000.
Mike has been a a developer at Napster and at his own lil' startup, Zabersoft, a development company he co-founded with offices in Los Angeles and Odense, Denmark. Mike is now a senior engineer at VMware.

He also enjoys his hobbies of playing pinball, bike riding, photography, and Domion on Friday nights (current favorite combo: Village + double Pirate Ship). He would get his own snooker table too if they weren't so darn big! He is also sad that he's forgotten the languages he's studied: French, Mandarin Chinese, and Japanese.

Mike was a VC MVP from 2005 to 2009.

Comments and Discussions