Pocket PC 2003 – Power ?

I seem to have been flying/presenting solidly for the last week or so - thankfully my Pocket PC Phone Edition has been able to keep sync'd with e-mail in Taiwan and in Hong Kong - the one issue I have with the Pocket PC is that I have absolutely no idea how much power is left in the device, I could click Start | Settings | System | Power - I'd prefer to just glance at the today screen to get this information, it would be extremely useful to have a custom Today Item that shows me the current power and also whether I'm charging the unit or not... We arrived at the Intercontinental hotel in Seoul late yesterday afternoon - after an excellent Korean meal in the hotel I decided to crack on with some work - I have slides to update ready for tomorrow's Windows Embedded Essentials (WEE) event, I have a spreadsheet to complete for my new manager (welcome on board Melanie!!) and an article to finish for MSDN - so I decided to write the custom today item instead... <G>

Here's the registry keys needed to have the power meter working...


It would be useful to be able to double click (tap) on a registry file and have it auto merge with the devices registry, since some of the marketing folks travelling with me might have some issues installing a Today item I also decided to write a simple Win32 application to copy the “MyToday.dll” file to the \Windows folder from an SD storage card, and to also setup the required registry information... here's the listing...

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

#include "stdafx.h"
#include <winreg.h>

int WINAPI WinMain( HINSTANCE hInstance,
     HINSTANCE hPrevInstance,
     LPTSTR    lpCmdLine,
     int       nCmdShow)
HKEY hKey;
DWORD dwDisposition;
DWORD dwFlags=0;
DWORD dwOptions=0;
DWORD dwEnabled=1;
DWORD dwOrder=14;
DWORD dwType=4;
TCHAR *tcReg=L"

DWORD dwSize=sizeof(DWORD);

long lRet=RegCreateKeyEx(HKEY_LOCAL_MACHINE,

if (lRet == ERROR_SUCCESS) { // Create Subkey goo here...
\\Storage Card\\MyToday.dll",L"\\Windows\\MyToday.dll",FALSE);
 MessageBox(NULL,L"Registry Enabled",L"Power Meter",MB_OK | MB_ICONINFORMATION);
} else {
 MessageBox(NULL,L"Cannot Create Registry Key!!",L"PowerReg",MB_OK | MB_ICONINFORMATION);

 return 0;

and of course we need the listing for the today item itself, this is simply a Win32 DLL - yes, I know there's information that shows how to write a custom today item in managed code, it seemed to be quicker to lift the example from the Pocket PC 2003 SDK and modify to suit my needs.

#include <windows.h>
#include <Todaycmn.h>

#include "resource.h"

HWND APIENTRY InitializeCustomItem(TODAYLISTITEM *ptli, HWND hwndParent);
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

HINSTANCE g_hInstance;
HWND g_hWndParent;
TCHAR szEvent[25] = TEXT("Count Down: ");  //String that specifies the thing we are counting down to
TCHAR szTime[25] = TEXT("\0");             //String to hold the time left.  We initialize this to empty
HBITMAP g_hBitmap;                    //Bitmap we use for painting the background
HDC g_hDCMem;                         //In memory DC used for painting the background
BOOL g_bGetBackgroundSurface = FALSE; //Boolean that is TRUE if the background changed
POINT g_oldPt;                        //Used to keep track of where our window is

HBITMAP hPowerBitmap;
TCHAR tcPower[50];
SYSTEM_POWER_STATUS_EX pStatus; // Power Status.


//The following two defines will probably be defined in a public header in the future.
//Please comment them out if you are having problems with building this sample.
#define TODAYM_GETCOLOR     (WM_USER + 100)    //Used to get the Today screen text color
#define TODAYCOLOR_TEXT     0x10000004         //Used to get the Today screen text color

// This is the WinProc for the dialog.  Does not do much in
// this example.               
BOOL APIENTRY CustomItemOptionsDlgProc(HWND hDlg, UINT message, UINT wParam, LONG lParam)
 switch (message)
   return TRUE;

  case WM_COMMAND:
   if (LOWORD(wParam) == IDOK)
    EndDialog(hDlg, LOWORD(wParam));
    return TRUE;
   return DefWindowProc(hDlg, message, wParam, lParam);
   return 0;

HWND APIENTRY InitializeCustomItem(TODAYLISTITEM *ptli,HWND hwndParent)
    WNDCLASS  wc;
    HWND  hWnd = NULL;
    if (ptli->fEnabled==0) return NULL;    //Return NULL if we are not enabled.
    g_hInstance = ptli->hinstDLL;         //Store instance handle in our global variable
    //Create our window class
    wc.style   = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc  = (WNDPROC) WndProc;
    wc.cbClsExtra  = 0;
    wc.cbWndExtra  = 0;
    wc.hInstance  = g_hInstance;
    wc.hIcon   = 0;
    wc.hCursor   = 0;
    wc.hbrBackground = (HBRUSH) COLOR_BACKGROUND;
    wc.lpszMenuName  = 0;
    wc.lpszClassName = TEXT("MyToday");
    g_oldPt.x = 0;        //Initialize our POINT structure that keeps track of our window location
    g_oldPt.y = 0;
    g_bGetBackgroundSurface = TRUE;    //Get the background to start with
    hWnd = CreateWindow(TEXT("MyToday"), TEXT("MyTodayScreen"), WS_VISIBLE | WS_CHILD,
        CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hwndParent, NULL, g_hInstance, NULL);
    g_hWndParent = hwndParent;
    return hWnd;


//This code checks to see if our window has changed locations.
BOOL HasPositionChanged (HWND hwnd)
    POINT pt;
    pt.x = 0;
    pt.y = 0;
    MapWindowPoints(hwnd, g_hWndParent, &pt, 1);
    if (pt.y != g_oldPt.y)
        g_oldPt.x = pt.x;
        g_oldPt.y = pt.y;
        return TRUE;
    return FALSE;

//Gets the backgound surface and puts it in a bitmap.  Allows us to do the transparent effect.
VOID GetBackgroundSurface(HWND hwnd)
    HDC parentDC = GetDC(g_hWndParent);
    // Create a memory device context compatible with the device.
    g_hDCMem = CreateCompatibleDC (parentDC);
    // Create a bitmap compatible with the device associated with the
    // device context.
    g_hBitmap = CreateCompatibleBitmap (parentDC, 240, WINDOWHEIGHT);
    SelectObject(g_hDCMem, g_hBitmap);

    BitBlt(g_hDCMem, 0, 0, 240, WINDOWHEIGHT, parentDC, g_oldPt.x, g_oldPt.y, SRCCOPY);
    ReleaseDC(g_hWndParent, parentDC);

//Draws the text
VOID PaintText(HWND hWnd, HDC hdc)
    RECT rt;
 HDC hDCTemp;
 HBITMAP hOldBitmap;
 BITMAP bmp;

    //First draw our background.
    BitBlt(hdc, 0, 0, 240, WINDOWHEIGHT, g_hDCMem, 0, 0, SRCCOPY);

 GetClientRect(hWnd, &rt);
    //The following gets us the text color for the today screen text.
    SetTextColor(hdc, SendMessage(g_hWndParent, TODAYM_GETCOLOR, TODAYCOLOR_TEXT, 0));

    rt.left += 30;
    rt.top += 2;
//    DrawText(hdc, tcPower, -1, &rt, DT_SINGLELINE);



//Gets the rectangle to just redraw the time.
//This helps reduce some flickering.
VOID GetClippingRect (HWND hWnd, RECT* rt)
    GetClientRect(hWnd, rt);
    rt->left += 125;
    rt->top += 2;
    rt->right -= 30;

//This is our paint function.  It only paints the whole
//window the first time around and whenever it moves.
VOID PaintAll(HWND hWnd, HDC hdc)
    RECT rt;

    if (HasPositionChanged(hWnd))
        rt.left = g_oldPt.x;
        rt.top = g_oldPt.y;
        rt.right = g_oldPt.x + 240;
        rt.bottom = g_oldPt.y + WINDOWHEIGHT;
        g_bGetBackgroundSurface = TRUE;
        ShowWindow(hWnd, SW_HIDE);
        InvalidateRect(g_hWndParent, &rt, TRUE);
        ShowWindow(hWnd, SW_SHOW);

    if (g_bGetBackgroundSurface == TRUE)
        g_bGetBackgroundSurface = FALSE;
        InvalidateRect(g_hWndParent, NULL, TRUE);
    PaintText(hWnd, hdc);

//Our main WndProc.  Does everything after initialization.
HDC hdc;

 switch (message)
  case WM_CREATE:
        case WM_TIMER:
   wsprintf(tcPower,L"Power at %ld%%",pStatus.BatteryLifePercent);
   if (pStatus.ACLineStatus == 1) { // On Mains Power.
    lstrcat(tcPower,L" - Charging");
            InvalidateRect(hWnd, NULL, FALSE);
        return TRUE;
        case WM_ERASEBKGND:
            //We return true here since we handle our own background painting.
            return TRUE;
            //We have no cache to clear so we ignore this message.
            //If the cyp member is set to 0 then you must set it to your windows height.
            //This makes sure the shell gives you a certain amout of room for your painting.
            if (((TODAYLISTITEM*)wParam)->cyp == 0)
                ((TODAYLISTITEM*)wParam)->cyp = WINDOWHEIGHT;  //the shell draws a line at the bottom of our window.
                return 1;
  case WM_PAINT:
            //Paint like you would in any other application.
   hdc = BeginPaint(hWnd, &ps);
            PaintAll(hWnd, hdc);
   EndPaint(hWnd, &ps);
   return DefWindowProc(hWnd, message, wParam, lParam);
   return 0;

There are two files you need to add to your project, a .DEF file, and a bitmap (defined as IDB_POWER in this project).

Here's the .DEF File...

InitializeCustomItem @ 240 NONAME
CustomItemOptionsDlgProc @ 241 NONAME

There are some updates I should make to this - right now the power meter flickers, I should double buffer everthing, I was also thinking of drawing the power meter rather than showing text - now that I have the basics running I think I prefer the text - see what you think...

- Mike



Comments (0)

Skip to main content