Поделиться через


State and Notifications Broker Sample (Compact 2013)

3/28/2014

This sample demonstrates how to use the State and Notifications Broker APIs.

Note

To make the following code example easier to read, security checking and error handling are not included. This code example should not be used in a release configuration unless it has been modified to include them.

Building the Sample

To build this sample, add all of the files below to a new solution and add in a standard icon file named BattStat.ico. Compile and link the solution. The executable BattStat.exe will be created.

Running the Sample

To run the sample, launch the BattStat.exe executable. A window with the main battery and backup battery status information will be displayed. The command line arguments are also displayed for demonstration purposes. The battery status will be updated as the information changes. For example, if the Pocket PC is placed in its cradle, the Battery State will change to "Charging". If you want to make the notifications persistant, then you can select "Persist" from the menu. The BattStat application will then be launched whenever a battery notification is received. To remove the persistent notification, select "Remove Persist" from the menu. To exit the application, select "Quit".

How the Sample Works

The sample registers four transient notifications when it is launched in the procedure RegisterWindows(). The notifications are for changes in main battery state, main battery strength, backup battery state, and backup battery strength. For demonstration purposes, a callback is used to receive changes in main battery state. The other notifications are received as custom window messages.

When registering the notifications, a series of definitions are used from the snapi.h header file. This file contains a set of definitions for each base notification - the registry root, the registry key, the registry value name. A bitmask indicating which bits are relevant is also defined for some notifications when it is needed.

The subroutine RegisterApps() is called when the "Persist" menu item is selected. The four battery notifications are again registered but this time are made persistent.

When a notification is received, the changed value is interpreted according to the relevant bitmask and value for the notification and the status window is updated.

BattStat.cpp

//
// BattStat.exe
//
// This sample demonstrates how to use the State and Notification Broker APIs.  More specifically, it
// demonstrates:
// - use of Window Message Notifications - RegistryNotifyWindow
// - use of Window Callback Notifications - RegistryNotifyCallback
// - use of Persistent Notifications - RegistryNotifyApp
// - use of the Main Battery and Backup Battery Strength and State notifications
// - how to apply bitmasks when registering the notifications 
// - how to extract and interpret the changed values using the proper bitmasks
// - how to include or exclude command line information in the Persistent Notifications
// - how to form the proper application path in a Persistent Notification  (ie  inserting quotes around the path)
// - how to unregister Message Notifications
// - how to unregister Callback Notifications
// - how to unregister Persistent Notifications
//
// The program is designed to show the user the current status of their main and backup battery.  
// Whenever a battery notification event is received, the battery status information will be updated
// in the display.
//
// To notification can be made persistent by selecting the "Persist" command from the menu.  Then, when
// a battery notification is sent, BattStat will be launched and display the updated status.
//
// The command line information is also included in the status area for demonstration purposes.
//



// BattStat.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "BattStat.h"
#include <windows.h>
#include <commctrl.h>
#include <regext.h>
#include <snapi.h>

#define MAX_LOADSTRING      100
#define STATUS_STRING_LEN   500

#define WM_OFFSET                 10000
#define WM_CHANGE_BATTSTRENGTH    (WM_OFFSET + 1)
#define WM_CHANGE_BATTSTATE       (WM_OFFSET + 2)
#define WM_CHANGE_BACKUPSTRENGTH  (WM_OFFSET + 3)
#define WM_CHANGE_BACKUPSTATE     (WM_OFFSET + 4)


#define IDC_BATTSTRENGTH    (WM_OFFSET + 200)
#define IDC_BATTSTATE       (WM_OFFSET + 201)
#define IDC_BACKUPSTRENGTH  (WM_OFFSET + 202)
#define IDC_BACKUPSTATE     (WM_OFFSET + 203)
#define IDC_CMDLINE         (WM_OFFSET + 204)

// Global Variables:
HINSTANCE g_hInst;      // Current instance

HWND g_hWndMenuBar;     // Menu bar handle
HWND g_hCurWndDialog;   // Primary Window Dialog

HWND g_hBattStrength;   // Status text windows
HWND g_hBattState;
HWND g_hBackupStrength;
HWND g_hBackupState;
HWND g_hCmdLine;

// RegistryNotifyApp names
const WCHAR c_wszAppBattStrengthName[]     = L"BattStat.BattStrength";
const WCHAR c_wszAppBattStateName[]        = L"BattStat.BattState";
const WCHAR c_wszAppBackupStrengthName[]   = L"BattStat.BackupStrength";
const WCHAR c_wszAppBackupStateName[]      = L"BattStat.BackupState";


#define NOTIFY_CNT 4
HREGNOTIFY  g_hNotify[NOTIFY_CNT];  // Handles to notifications



// Forward declarations of functions included in this code module:
ATOM    MyRegisterClass(HINSTANCE, LPTSTR);
BOOL    InitInstance(HINSTANCE, int);
LRESULT CALLBACK  WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK  About(HWND, UINT, WPARAM, LPARAM);
HRESULT RegisterWindows();
HRESULT RegisterApps();
HRESULT UnregisterWindows();
HRESULT UnregisterApps();
void    BattStateCallback(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData);

//
//  FUNCTION: int WINAPI WinMain(HINSTANCE hInstance,
//                   HINSTANCE hPrevInstance,
//                   LPTSTR    lpCmdLine,
//                   int       nCmdShow)
//
//  PURPOSE: Main loop.
//
//  COMMENTS:
//
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPrevInstance,
                   LPTSTR    lpCmdLine,
                   int       nCmdShow)
{
  MSG msg;

  // Perform application initialization.
  if (!InitInstance(hInstance, nCmdShow)) 
  {
    return FALSE;
  }

  HACCEL hAccelTable;
  hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_BATTSTAT));

  // Main message loop.
  while (GetMessage(&msg, NULL, 0, 0)) 
  {
    if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) 
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return (int) msg.wParam;
}

//
//  FUNCTION: ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
//
//  PURPOSE: Registers the window class.
//
//  COMMENTS:
//
ATOM MyRegisterClass(HINSTANCE hInstance, LPTSTR szWindowClass)
{
  WNDCLASS wc;

  wc.style         = CS_HREDRAW | CS_VREDRAW;
  wc.lpfnWndProc   = WndProc;
  wc.cbClsExtra    = 0;
  wc.cbWndExtra    = 0;
  wc.hInstance     = hInstance;
  wc.hIcon         = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_BATTSTAT));
  wc.hCursor       = 0;
  wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
  wc.lpszMenuName  = 0;
  wc.lpszClassName = szWindowClass;

  return RegisterClass(&wc);
}


 
//
//  FUNCTION: void GetBattStateStr(DWORD dwBattState, LPTSTR  pszBattStateStr)
//
//  PURPOSE: Form the battery state string from the given battery state flag.
//
//  COMMENTS:
//

void GetBattStateStr(DWORD dwBattState, LPTSTR  pszBattStateStr)
{
  if (dwBattState == 0)
  {
    StringCchCat(pszBattStateStr, STATUS_STRING_LEN, L"Normal");
  }
  else
  {
    // Check each bit; specific battery drivers may set different combinations of bits.
    if (dwBattState & 1)
    {
      StringCchCat(pszBattStateStr, STATUS_STRING_LEN, L"Not Present ");
    }

    if (dwBattState & 2)
    {
      StringCchCat(pszBattStateStr, STATUS_STRING_LEN, L"Charging ");
    }

    if (dwBattState & 4)
    {
      StringCchCat(pszBattStateStr, STATUS_STRING_LEN, L"Low ");
    }

    if (dwBattState & 8)
    {
      StringCchCat(pszBattStateStr, STATUS_STRING_LEN, L"Critical");
    }
  }
}



//
//  FUNCTION: void UpdateBattState(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, 
//                                 DWORD dwBitMask, int nControlID)
//
//  PURPOSE:  Update the given battery state.
//
//  COMMENTS:
//
void UpdateBattState(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, DWORD dwBitMask, int nControlID)
{
  HRESULT hr;
  DWORD dwRegValue;
  DWORD dwBattState;
  TCHAR szBattStateStr[STATUS_STRING_LEN];
  
  StringCchCopy(szBattStateStr, STATUS_STRING_LEN, L"");

  // Read the new value.
  hr = RegistryGetDWORD(hKey, wszSubKey, wszName, &dwRegValue);

  if (hr == S_OK)
  {
    // Only look at specified bits.
    dwBattState = dwRegValue  & dwBitMask;
    GetBattStateStr(dwBattState, szBattStateStr);
  }

  // Update the status text.
  SetDlgItemText(g_hCurWndDialog, nControlID, szBattStateStr);
}


 
//
//  FUNCTION: void UpdateBattStrength(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, 
//                                    DWORD dwBitMask, int nControlID)
//
//  PURPOSE: Update the given battery strength level.
//
//  COMMENTS:
//
void UpdateBattStrength(HKEY hKey, LPCWSTR wszSubKey, LPCWSTR wszName, DWORD dwBitMask, int nControlID)
{
  HRESULT hr;
  DWORD dwRegValue;
  ULONG dwBattStrength;
  TCHAR szBattStrengthStr[STATUS_STRING_LEN];
  
  StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"");

  // Read the new value from the registry.
  hr = RegistryGetDWORD(hKey, wszSubKey, wszName, &dwRegValue);

  if (hr == S_OK)
  {
    // Get the value of the highword and shift the bits over to read the actual value.
    dwBattStrength = (dwRegValue  & dwBitMask) >> 16;

    // Check the value to get the appropriate string.
    if (dwBattStrength == 0)
    {
      StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"Very Low");
    }
    else if (dwBattStrength == 21)
    {
      StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"Low");
    }
    else if (dwBattStrength == 41)
    {
      StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"Medium");
    }
    else if (dwBattStrength == 61)
    {
      StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"High");
    }
    else if (dwBattStrength == 81)
    {
      StringCchCopy(szBattStrengthStr, STATUS_STRING_LEN, L"Very High");
    }

  }

  // Update the status text.
  SetDlgItemText(g_hCurWndDialog, nControlID, szBattStrengthStr);
}


//
//  FUNCTION: void UpdateAll()
//
//  PURPOSE: Update all the battery values.
//
//  COMMENTS:
//
void UpdateAll()
{
  UpdateBattStrength(SN_POWERBATTERYSTRENGTH_ROOT, SN_POWERBATTERYSTRENGTH_PATH, SN_POWERBATTERYSTRENGTH_VALUE, SN_POWERBATTERYSTRENGTH_BITMASK, IDC_BATTSTRENGTH);
  UpdateBattState(SN_POWERBATTERYSTATE_ROOT, SN_POWERBATTERYSTATE_PATH, SN_POWERBATTERYSTATE_VALUE, SN_POWERBATTERYSTATE_BITMASK, IDC_BATTSTATE);
  UpdateBattStrength(SN_POWERBATTERYBACKUPSTRENGTH_ROOT, SN_POWERBATTERYBACKUPSTRENGTH_PATH, SN_POWERBATTERYBACKUPSTRENGTH_VALUE, SN_POWERBATTERYBACKUPSTRENGTH_BITMASK, IDC_BACKUPSTRENGTH);
  UpdateBattState(SN_POWERBATTERYBACKUPSTATE_ROOT, SN_POWERBATTERYBACKUPSTATE_PATH, SN_POWERBATTERYBACKUPSTATE_VALUE, SN_POWERBATTERYBACKUPSTATE_BITMASK, IDC_BACKUPSTATE);
  SetDlgItemText(g_hCurWndDialog, IDC_CMDLINE, GetCommandLine());
}




//
//   FUNCTION: InitInstance(HINSTANCE, int)
//
//   PURPOSE: Saves instance handle and creates main window.
//
//   COMMENTS:
//
//        In this function, we save the instance handle in a global variable and
//        create and display the main program window.
//
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
  HWND hWnd;
  TCHAR szTitle[MAX_LOADSTRING];        // Title bar text
  TCHAR szWindowClass[MAX_LOADSTRING];  // Main window class name

  // Store instance handle in our global variable.
  g_hInst = hInstance;                  

  // SHInitExtraControls should be called once during your application's initialization to initialize any
  // of the Pocket PC special controls such as CAPEDIT and SIPPREF.
  SHInitExtraControls();

  LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); 
  LoadString(hInstance, IDC_BATTSTAT, szWindowClass, MAX_LOADSTRING);

  //If it is already running, then focus on the window, and exit.
  hWnd = FindWindow(szWindowClass, szTitle);  

  if (hWnd) 
  {
    // Set focus to foremost child window.
    // The "| 0x00000001" is used to bring any owned windows to the foreground and
    // activate them.
    SetForegroundWindow((HWND)((ULONG) hWnd | 0x00000001));

    return 0;
  } 

  if (!MyRegisterClass(hInstance, szWindowClass))
  {
    return FALSE;
  }

  hWnd = CreateWindow(szWindowClass, szTitle, WS_VISIBLE,
      CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

  if (!hWnd)
  {
      return FALSE;
  }

  g_hCurWndDialog = hWnd;

  // When the main window is created using CW_USEDEFAULT the height of the menubar (if one
  // is created is not taken into account). So we resize the window after creating it
  // if a menubar is present
  if (g_hWndMenuBar)
  {
    RECT rc;
    RECT rcMenuBar;

    GetWindowRect(hWnd, &rc);
    GetWindowRect(g_hWndMenuBar, &rcMenuBar);
    rc.bottom -= (rcMenuBar.bottom - rcMenuBar.top);

    MoveWindow(hWnd, rc.left, rc.top, rc.right-rc.left, rc.bottom-rc.top, FALSE);
  }

  ShowWindow(hWnd, nCmdShow);
  UpdateWindow(hWnd);

  // Create the status text windows - the labels and the current value.
  CreateWindow(TEXT("STATIC"), 
         TEXT("Battery Strength : "), 
         WS_VISIBLE,
         10, 20, 110, 14, 
         hWnd, NULL, hInstance, NULL);

  g_hBattStrength = CreateWindow(TEXT("STATIC"), 
         TEXT(""), 
         WS_VISIBLE,
         10, 35, 200, 14, 
         hWnd, (HMENU)IDC_BATTSTRENGTH, hInstance, NULL);

  CreateWindow(TEXT("STATIC"), 
         TEXT("Battery State : "), 
         WS_VISIBLE,
         10, 60, 110, 14, 
         hWnd, NULL, hInstance, NULL);

  g_hBattState = CreateWindow(TEXT("STATIC"), 
         TEXT(""), 
         WS_VISIBLE,
         10, 75, 200, 14, 
         hWnd, (HMENU)IDC_BATTSTATE, hInstance, NULL);

  CreateWindow(TEXT("STATIC"), 
         TEXT("Backup Strength : "), 
         WS_VISIBLE,
         10, 100, 110, 14, 
         hWnd, NULL, hInstance, NULL);

  g_hBackupStrength = CreateWindow(TEXT("STATIC"), 
         TEXT(""), 
         WS_VISIBLE,
         10, 115, 200, 14, 
         hWnd, (HMENU)IDC_BACKUPSTRENGTH, hInstance, NULL);

  CreateWindow(TEXT("STATIC"), 
         TEXT("Backup State : "), 
         WS_VISIBLE,
         10, 140, 110, 14, 
         hWnd, NULL, hInstance, NULL);

  g_hBackupState = CreateWindow(TEXT("STATIC"), 
         TEXT(""), 
         WS_VISIBLE,
         10, 155, 200, 14, 
         hWnd, (HMENU)IDC_BACKUPSTATE, hInstance, NULL);

  CreateWindow(TEXT("STATIC"), 
         TEXT("Command Line : "), 
         WS_VISIBLE,
         10, 200, 110, 14, 
         hWnd, NULL, hInstance, NULL);

  g_hCmdLine = CreateWindow(TEXT("STATIC"), 
         TEXT(""), 
         WS_VISIBLE,
         10, 215, 200, 14, 
         hWnd, (HMENU)IDC_CMDLINE, hInstance, NULL);

  // Register our window notifications.
  RegisterWindows();

  // Initialize the display of the battery values.
  UpdateAll();

  return TRUE;
}



//
//  FUNCTION: LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
//
//  PURPOSE:  Processes messages for the main window.
//
//  WM_COMMAND  - process the application menu
//  WM_PAINT  - Paint the main window
//  WM_DESTROY  - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
  int wmId, wmEvent;
  PAINTSTRUCT ps;
  HDC hdc;

  static SHACTIVATEINFO s_sai;

  switch (message) 
  {
    case WM_COMMAND:
      wmId    = LOWORD(wParam); 
      wmEvent = HIWORD(wParam); 

      // Parse the menu selections.
      switch (wmId)
      {
        case IDM_HELP_ABOUT:
          DialogBox(g_hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, About);

          break;

        case IDM_OK:
          // Unregister our window notifications and exit.
          UnregisterWindows();
          SendMessage (hWnd, WM_CLOSE, 0, 0);        

          break;

        case ID_MENU_UPDATE:
          // Manually update all battery status values.
          UpdateAll();

          break;

        case ID_MENU_PERSIST:
          // Register the app notifications.
          RegisterApps();

          break;

        case ID_MENU_REMOVEPERSIST:
          // Unregister the app notifications.
          UnregisterApps();

          break;

        default:
          return DefWindowProc(hWnd, message, wParam, lParam);
      }

      break;

    case WM_CREATE:
      SHMENUBARINFO mbi;

      memset(&mbi, 0, sizeof(SHMENUBARINFO));
      mbi.cbSize     = sizeof(SHMENUBARINFO);
      mbi.hwndParent = hWnd;
      mbi.nToolBarId = IDR_MENU;
      mbi.hInstRes   = g_hInst;

      if (!SHCreateMenuBar(&mbi)) 
      {
          g_hWndMenuBar = NULL;
      }
      else
      {
          g_hWndMenuBar = mbi.hwndMB;
      }

      // Initialize the shell activate info structure.
      memset(&s_sai, 0, sizeof (s_sai));
      s_sai.cbSize = sizeof (s_sai);

      break;

    case WM_PAINT:
      hdc = BeginPaint(hWnd, &ps);
      
      // TODO: Add any drawing code here...
      
      EndPaint(hWnd, &ps);

      break;

    case WM_DESTROY:
      CommandBar_Destroy(g_hWndMenuBar);
      PostQuitMessage(0);
      break;

    case WM_ACTIVATE:
      // Notify shell of our activate message.
      SHHandleWMActivate(hWnd, wParam, lParam, &s_sai, FALSE);

      break;

    case WM_SETTINGCHANGE:
      SHHandleWMSettingChange(hWnd, wParam, lParam, &s_sai);

      break;

    case WM_CHANGE_BATTSTRENGTH:
      // Main battery strength value changed.
      UpdateBattStrength(SN_POWERBATTERYSTRENGTH_ROOT, SN_POWERBATTERYSTRENGTH_PATH, SN_POWERBATTERYSTRENGTH_VALUE, SN_POWERBATTERYSTRENGTH_BITMASK, IDC_BATTSTRENGTH);

      break;

    case WM_CHANGE_BATTSTATE:
      // Main battery state value changed.
      UpdateBattState(SN_POWERBATTERYSTATE_ROOT, SN_POWERBATTERYSTATE_PATH, SN_POWERBATTERYSTATE_VALUE, SN_POWERBATTERYSTATE_BITMASK, IDC_BATTSTATE);

      break;

    case WM_CHANGE_BACKUPSTRENGTH:
      // Backup battery strength value changed.
      UpdateBattStrength(SN_POWERBATTERYBACKUPSTRENGTH_ROOT, SN_POWERBATTERYBACKUPSTRENGTH_PATH, SN_POWERBATTERYBACKUPSTRENGTH_VALUE, SN_POWERBATTERYBACKUPSTRENGTH_BITMASK, IDC_BACKUPSTRENGTH);

      break;

    case WM_CHANGE_BACKUPSTATE:
      // Backup battery state value changed.
      UpdateBattState(SN_POWERBATTERYBACKUPSTATE_ROOT, SN_POWERBATTERYBACKUPSTATE_PATH, SN_POWERBATTERYBACKUPSTATE_VALUE, SN_POWERBATTERYBACKUPSTATE_BITMASK, IDC_BACKUPSTATE);

      break;

    default:
      return DefWindowProc(hWnd, message, wParam, lParam);
  }

  return 0;

}


//
//  FUNCTION: INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
//
//  PURPOSE: Message handler for about box.
//
//  COMMENTS:
//
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
  switch (message)
  {
    case WM_INITDIALOG:
        {
            // Create a Done button and size it.  
            SHINITDLGINFO shidi;
            shidi.dwMask = SHIDIM_FLAGS;
            shidi.dwFlags = SHIDIF_DONEBUTTON | SHIDIF_SIPDOWN | SHIDIF_SIZEDLGFULLSCREEN | SHIDIF_EMPTYMENU;
            shidi.hDlg = hDlg;
            SHInitDialog(&shidi);
        }
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return TRUE;
        }
        break;

    case WM_CLOSE:
        EndDialog(hDlg, message);
        return TRUE;

#ifdef _DEVICE_RESOLUTION_AWARE
    case WM_SIZE:
      {
        DRA::RelayoutDialog(
            g_hInst, 
            hDlg, 
            DRA::GetDisplayMode() != DRA::Portrait ? MAKEINTRESOURCE(IDD_ABOUTBOX_WIDE) : MAKEINTRESOURCE(IDD_ABOUTBOX));
      }

      break;

#endif
  }

  return (INT_PTR)FALSE;

}


//
//  FUNCTION: HRESULT RegisterWindows()
//
//  PURPOSE: Register the window notifications.
//
//  COMMENTS:
//
HRESULT RegisterWindows()
{
  HRESULT hr;
  NOTIFICATIONCONDITION nc;

  // Make sure we aren't already registered.
  UnregisterWindows();

  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYSTRENGTH_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register battery strength notification.
  hr = RegistryNotifyWindow(
                SN_POWERBATTERYSTRENGTH_ROOT,
                SN_POWERBATTERYSTRENGTH_PATH,
                SN_POWERBATTERYSTRENGTH_VALUE,
                g_hCurWndDialog, 
                WM_CHANGE_BATTSTRENGTH,       // This notification uses a custom window message.
                0,
                &nc,
                &g_hNotify[0]
                );

  if (FAILED(hr))
  {
      goto Error;
  }

  // Notify us of any change in the value and set the bitmask of the value to check.
  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYSTATE_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register battery state notification.
  hr = RegistryNotifyCallback(
                SN_POWERBATTERYSTATE_ROOT,
                SN_POWERBATTERYSTATE_PATH,
                SN_POWERBATTERYSTATE_VALUE,
                BattStateCallback,          // This notification uses a callback.
                0,       
                &nc,
                &g_hNotify[1]
                );

  if (FAILED(hr))
  {
    goto Error;
  }

  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYBACKUPSTRENGTH_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register backup battery strength notification.
  hr = RegistryNotifyWindow(
                SN_POWERBATTERYBACKUPSTRENGTH_ROOT,
                SN_POWERBATTERYBACKUPSTRENGTH_PATH,
                SN_POWERBATTERYBACKUPSTRENGTH_VALUE,
                g_hCurWndDialog, 
                WM_CHANGE_BACKUPSTRENGTH,
                0,
                &nc,
                &g_hNotify[2]
                );

  if (FAILED(hr))
  {
    goto Error;
  }

  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYBACKUPSTATE_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register backup battery state notification.
  hr = RegistryNotifyWindow(
                SN_POWERBATTERYBACKUPSTATE_ROOT,
                SN_POWERBATTERYBACKUPSTATE_PATH,
                SN_POWERBATTERYBACKUPSTATE_VALUE,
                g_hCurWndDialog, 
                WM_CHANGE_BACKUPSTATE,
                0,
                &nc,
                &g_hNotify[3]
                );

  if (FAILED(hr))
  {
    goto Error;
  }


Error:
    return hr;
}



//
//  FUNCTION: HRESULT RegisterApps()
//
//  PURPOSE: Register the application notifications.
//
//  COMMENTS:
//
HRESULT RegisterApps()
{
  HRESULT hr;
  NOTIFICATIONCONDITION nc;
  TCHAR szExePath[MAX_PATH];
  TCHAR szThisPath[MAX_PATH];

  // Make sure we aren't already registered.
  UnregisterApps();

  // Get the path to this application.
  GetModuleFileName(NULL, szThisPath, MAX_PATH);

  // Need to put a quote before and after the path, in case the path contains spaces.
  StringCchCopy(szExePath, MAX_PATH, L"\"");
  StringCchCat(szExePath, MAX_PATH, szThisPath);
  StringCchCat(szExePath, MAX_PATH, L"\"");

  // Notify us of any change in the value and set the bitmask of the value to check.
  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYSTRENGTH_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register battery strength notification.
  hr = RegistryNotifyApp(
                SN_POWERBATTERYSTRENGTH_ROOT,
                SN_POWERBATTERYSTRENGTH_PATH,
                SN_POWERBATTERYSTRENGTH_VALUE,
                c_wszAppBattStrengthName,
                szExePath,                      // Path to our app so that BattStat will be launched if it is not already running.
                NULL,
                NULL,
                WM_CHANGE_BATTSTRENGTH,
                RNAF_NONAMEONCMDLINE,         // Don't pass along anything on the command line.
                &nc
                );

  if (FAILED(hr))
  {
    goto Error;
  }

  
  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYSTATE_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register battery state notification.
  hr = RegistryNotifyApp(
                SN_POWERBATTERYSTATE_ROOT,
                SN_POWERBATTERYSTATE_PATH,
                SN_POWERBATTERYSTATE_VALUE,
                c_wszAppBattStateName,
                szExePath,
                NULL,
                NULL,
                WM_CHANGE_BATTSTATE,
                0,                      // Command line will contain   "/notify <notification name>".
                &nc
                );

  if (FAILED(hr))
  {
    goto Error;
  }

  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYBACKUPSTRENGTH_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register backup battery strength notification.
  hr = RegistryNotifyApp(
                SN_POWERBATTERYBACKUPSTRENGTH_ROOT,
                SN_POWERBATTERYBACKUPSTRENGTH_PATH,
                SN_POWERBATTERYBACKUPSTRENGTH_VALUE,
                c_wszAppBackupStrengthName,
                szExePath,
                NULL,
                NULL,
                WM_CHANGE_BACKUPSTRENGTH,
                RNAF_NONAMEONCMDLINE,           // Don't pass along anything on the command line.
                &nc
                );

  if (FAILED(hr))
  {
    goto Error;
  }

  nc.ctComparisonType = REG_CT_ANYCHANGE;
  nc.dwMask           = SN_POWERBATTERYBACKUPSTATE_BITMASK;
  nc.TargetValue.dw   = 0;

  // Register backup battery state notification.
  hr = RegistryNotifyApp(
                SN_POWERBATTERYBACKUPSTATE_ROOT,
                SN_POWERBATTERYBACKUPSTATE_PATH,
                SN_POWERBATTERYBACKUPSTATE_VALUE,
                c_wszAppBackupStateName,
                szExePath,
                NULL,
                NULL,
                WM_CHANGE_BACKUPSTATE,
                0,                        // Command line will contain   "/notify <notification name>".
                &nc
                );

  if (FAILED(hr))
  {
    goto Error;
  }

Error:

  return hr;
}


//
//  FUNCTION: HRESULT UnregisterWindows()
//
//  PURPOSE: Unregister all window notifications.
//
//  COMMENTS:
//
HRESULT UnregisterWindows()
{
  long lNotifyIndx;

  // For each notification handle:
  for (lNotifyIndx=0; lNotifyIndx < NOTIFY_CNT; lNotifyIndx++)
  {
    if (g_hNotify[lNotifyIndx] != NULL)
    {
      // Close off the notification.
      RegistryCloseNotification(g_hNotify[lNotifyIndx]);
    }

    g_hNotify[lNotifyIndx] = 0;
  }

  return S_OK;
}

//
//  FUNCTION: HRESULT UnregisterApps()
//
//  PURPOSE: Unregister all application notifications.
//
//  COMMENTS:
//
HRESULT UnregisterApps()
{

  RegistryStopNotification(c_wszAppBattStrengthName);
  RegistryStopNotification(c_wszAppBattStateName);
  RegistryStopNotification(c_wszAppBackupStrengthName);
  RegistryStopNotification(c_wszAppBackupStateName);

  return S_OK;
}


//
//  FUNCTION: void BattStateCallback(HREGNOTIFY hNotify, DWORD dwUserData, 
//                                   const PBYTE pData, const UINT cbData)
//
//  PURPOSE: Callback function that is called when battery state changes.
//
//  COMMENTS:
//
void BattStateCallback(HREGNOTIFY hNotify, DWORD dwUserData, const PBYTE pData, const UINT cbData)
{
  DWORD dwBattState = 0;
  PDWORD pdwData;
  TCHAR szBattStateStr[STATUS_STRING_LEN];
    
  StringCchCopy(szBattStateStr, STATUS_STRING_LEN, L"");

  // Get the new value.
  pdwData = (DWORD *)pData;
  dwBattState = *pdwData;

  // Apply our bitmap mask and form the battery state as a string.
  dwBattState = dwBattState & SN_POWERBATTERYSTATE_BITMASK;
  GetBattStateStr(dwBattState, szBattStateStr);

  // Update the status text.
  SetDlgItemText(g_hCurWndDialog, IDC_BATTSTATE, szBattStateStr);

}

BattStat.h

#pragma once
#include "resourceppc.h"

resourceppc.h

//{{NO_DEPENDENCIES}}
// Microsoft Visual C++ generated include file.
// Used by BattStatppc.rc
//
#define IDS_APP_TITLE                   1
#define IDC_BATTSTAT                    2
#define IDI_BATTSTAT                    101
#define IDR_MENU                        102
#define IDS_OK                          103
#define IDS_HELP                        104
#define IDD_ABOUTBOX                    105
#define IDD_ABOUTBOX_WIDE               106
#define IDC_STATIC_1                    201
#define IDC_STATIC_2                    202
#define IDC_STATIC_3                    203
#define ID_MENU_UPDATE                  32771
#define ID_MENU_PERSIST                 32772
#define ID_MENU_REMOVEPERSIST           32773
#define IDM_OK                          40000
#define IDM_HELP                        40001
#define IDM_HELP_ABOUT                  40002
#define IDC_STATIC                      -1

// Next default values for new objects
// 
#ifdef APSTUDIO_INVOKED
#ifndef APSTUDIO_READONLY_SYMBOLS
#define _APS_NO_MFC                     1
#define _APS_NEXT_RESOURCE_VALUE        129
#define _APS_NEXT_COMMAND_VALUE         32774
#define _APS_NEXT_CONTROL_VALUE         1000
#define _APS_NEXT_SYMED_VALUE           110
#endif
#endif

stdafx.h

// stdafx.h : include file for standard system include files,
// or project specific include files that are used frequently, but
// are changed infrequently
//

#pragma once

#ifdef _X86_
   #pragma comment(linker, "/nodefaultlib:libc.lib")
   #pragma comment(linker, "/nodefaultlib:libcd.lib")
   #pragma comment(linker, "/nodefaultlib:oldnames.lib")
#endif

// NOTE - this value is not strongly correlated to the Windows Embedded Compact OS version being targeted
#define WINVER _WIN32_WCE

#include <ceconfig.h>

// Windows Header Files:
#include <windows.h>

// C RunTime Header Files
#include <stdlib.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>

#if defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP)
#ifndef _DEVICE_RESOLUTION_AWARE
#define _DEVICE_RESOLUTION_AWARE
#endif
#endif

#ifdef _DEVICE_RESOLUTION_AWARE
#include "DeviceResolutionAware.h"
#endif

#include <altcecrt.h>

#ifdef _DLL // /MD
   #if defined(_DEBUG)
      #pragma comment(lib, "msvcrtd.lib")
   #else
      #pragma comment(lib, "msvcrt.lib")
   #endif
#else // /MT
   #if defined(_DEBUG)
      #pragma comment(lib, "libcmtd.lib")
   #else
      #pragma comment(lib, "libcmt.lib")
   #endif
#endif

#if _WIN32_WCE < 0x500 && ( defined(WIN32_PLATFORM_PSPC) || defined(WIN32_PLATFORM_WFSP) )
   #pragma comment(lib, "ccrtrtti.lib")
   #ifdef _X86_   
      #if defined(_DEBUG)
         #pragma comment(lib, "libcmtx86d.lib")
      #else
         #pragma comment(lib, "libcmtx86.lib")
      #endif
   #endif
#endif

// TODO: reference additional headers your program requires here

BattStatppc.rc

// Microsoft Visual C++ generated resource script.
//
#include "resourceppc.h"

#define APSTUDIO_READONLY_SYMBOLS
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 2 resource.
//
#define APSTUDIO_HIDDEN_SYMBOLS
#include "resdefce.h"
#undef APSTUDIO_HIDDEN_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
#undef APSTUDIO_READONLY_SYMBOLS

/////////////////////////////////////////////////////////////////////////////
// English (U.S.) resources

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
#ifdef _WIN32
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#pragma code_page(1252)
#endif //_WIN32

/////////////////////////////////////////////////////////////////////////////
//
// Icon
//

// Icon with lowest ID value placed first to ensure application icon
// remains consistent on all systems.
IDI_BATTSTAT            ICON                    "BattStat.ico"

/////////////////////////////////////////////////////////////////////////////
//
// Menu
//

IDR_MENU MENU 
BEGIN
    POPUP "Menu"
    BEGIN
        MENUITEM "About",                       IDM_HELP_ABOUT
        MENUITEM SEPARATOR
        MENUITEM "Update",                      ID_MENU_UPDATE
        MENUITEM "Persist",                     ID_MENU_PERSIST
        MENUITEM "Remove Persist",              ID_MENU_REMOVEPERSIST
    END
END


/////////////////////////////////////////////////////////////////////////////
//
// Accelerator
//

IDC_BATTSTAT ACCELERATORS 
BEGIN
    "A",            IDM_HELP_ABOUT,         VIRTKEY, CONTROL, NOINVERT
    "Q",            IDM_OK,                 VIRTKEY, CONTROL, NOINVERT
END


/////////////////////////////////////////////////////////////////////////////
//
// Dialog
//

IDD_ABOUTBOX DIALOG  0, 0, 156, 129
STYLE DS_SETFONT | DS_FIXEDSYS | WS_POPUP | WS_CAPTION
EXSTYLE 0x80000000L
CAPTION "About BattStat"
FONT 8, "MS Shell Dlg"
BEGIN
    ICON            IDI_BATTSTAT,IDC_STATIC_1,12,12,21,20,SS_REALSIZEIMAGE
    LTEXT           "BattStat Version 1.0",IDC_STATIC_2,12,36,70,8,SS_NOPREFIX
    LTEXT           "Copyright (C) 2005",IDC_STATIC_3,12,48,66,8
END

IDD_ABOUTBOX_WIDE DIALOG  0, 0, 210, 129
STYLE DS_SETFONT | WS_POPUP | WS_CAPTION
EXSTYLE 0x80000000L
CAPTION "About BattStat"
FONT 8, "MS Shell Dlg"
BEGIN
    ICON            IDI_BATTSTAT,IDC_STATIC_1,12,12,21,20,SS_REALSIZEIMAGE
    LTEXT           "BattStat Version 1.0",IDC_STATIC_2,48,12,66,8,SS_NOPREFIX
    LTEXT           "Copyright (C) 2005",IDC_STATIC_3,48,24,66,8
END


/////////////////////////////////////////////////////////////////////////////
//
// DESIGNINFO
//

#ifdef APSTUDIO_INVOKED
GUIDELINES DESIGNINFO 
BEGIN
    IDD_ABOUTBOX, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 149
        TOPMARGIN, 7
        BOTTOMMARGIN, 122
    END

    IDD_ABOUTBOX_WIDE, DIALOG
    BEGIN
        LEFTMARGIN, 7
        RIGHTMARGIN, 203
        TOPMARGIN, 7
        BOTTOMMARGIN, 122
    END
END
#endif    // APSTUDIO_INVOKED


#ifdef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// TEXTINCLUDE
//

1 TEXTINCLUDE 
BEGIN
    "resourceppc.h\0"
END

2 TEXTINCLUDE 
BEGIN
    "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "#include ""resdefce.h""\r\n"
    "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
    "\0"
END

3 TEXTINCLUDE 
BEGIN
    "\r\n"
    "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n"
    "LANGUAGE 9, 1\r\n"
    "#pragma code_page(1252)\r\n"
    "#include ""BattStatppc.rc2""  // non-Microsoft Visual C++ edited resources\r\n"
    "#endif\r\n"
    "\0"
END

#endif    // APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
//
// String Table
//

STRINGTABLE 
BEGIN
    IDS_APP_TITLE           "BattStat"
    IDC_BATTSTAT            "BATTSTAT"
END

STRINGTABLE 
BEGIN
    IDS_OK                  "Quit"
    IDS_HELP                "Menu"
END

#endif    // English (U.S.) resources
/////////////////////////////////////////////////////////////////////////////



#ifndef APSTUDIO_INVOKED
/////////////////////////////////////////////////////////////////////////////
//
// Generated from the TEXTINCLUDE 3 resource.
//

#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
LANGUAGE 9, 1
#pragma code_page(1252)
#include "BattStatppc.rc2"  // non-Microsoft Visual C++ edited resources
#endif

/////////////////////////////////////////////////////////////////////////////
#endif    // not APSTUDIO_INVOKED

BattStatppc.rc2

//
// BattStatPPC.RC2 - resources Microsoft Visual C++ does not edit directly
//

#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED


/////////////////////////////////////////////////////////////////////////////
// Add manually edited resources here...

/////////////////////////////////////////////////////////////////////////////
HI_RES_AWARE CEUX {1}   // turn off the emulation layer
         // Remove this resource to enable pixel-
         // doubling on platforms that support it
/////////////////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////////////////
//
// RCDATA
//

IDR_MENU RCDATA
BEGIN
    IDR_MENU, 
    2,

    I_IMAGENONE, IDM_OK, TBSTATE_ENABLED, TBSTYLE_BUTTON | TBSTYLE_AUTOSIZE,
    IDS_OK, 0, NOMENU,
    
    I_IMAGENONE, IDM_HELP, TBSTATE_ENABLED, TBSTYLE_DROPDOWN | TBSTYLE_AUTOSIZE,
    IDS_HELP, 0, 0,
END

stdafx.cpp

// stdafx.cpp : source file that includes just the standard includes
// BattStat.pch will be the pre-compiled header
// stdafx.obj will contain the pre-compiled type information

#include "stdafx.h"

// TODO: reference any additional headers you need in STDAFX.H
// and not in this file

See Also

Other Resources

Core OS Services