Two for the Road
Today the Pocket PC, Tomorrow the World!

John Kennedy
Microsoft Corporation

September 12, 2001

Download the Today.exe sample file.

Thankfully, I'm back to full health (at least physically), and I've been able to get mobile again. Of course, by mobile, I mean able to walk to the alehouse across the road, but I'm thankful all the same. Of course, in an ideal world, the alehouse would share the same wireless Internet access facilities as the Starbucks, and then I wouldn't have to go home all weekend, but I'm not sure my wife would share this sentiment.

This month we're going to take a good look at one of my very favorite aspects of Pocket PC development—the amazingly flexible Today screen. While the Pocket PC tries to comfort users with a familiar desktop-style Microsoft Windows® user experience, there are times when something designed specifically for a PDA is a better idea. This is certainly the reasoning behind the Today screen, which provides an at-a-glance summary of the day's tasks, e-mails, and appointments. It's fair to think of the Pocket PC's Today screen as the equivalent to a standard Windows desktop. That said, it's probably more accurate to consider the Today screen as a unique, stand-alone application—an application that we can exploit.

The Today screen is often used as the default display. When the Pocket PC is reset, or when no other programs or settings windows have been opened, the Today screen is the window at the forefront of the display. The Pocket PC can also default to the Today screen if the device has been powered off for 1 to 12 hours (a value defined in the Start/Settings/Today control panel dialog).

Figure 1. If you want the Today screen visible when you switch on your device, or when you leave it in the cradle, change this setting from Start/Settings/Today.

Look closely at a typical Today screen and you'll see that it has six different sections or components. They are:

  1. The date
  2. The title bar (which displays the word Today)
  3. The owner information display (your name)
  4. Calendar information
  5. Inbox information
  6. Tasks information

Figure 2. Notice how the Today screen consists of different components. The date and "today" logo are actually two separate components.

You can toggle all components on and off from the Start/Settings/Today dialog. You can also alter the position of the last four, and tweak a few options in the Calendar and Tasks setting.

Figure 3. Several of the Today components have a separate options dialog. We'll be making use of this in our own components.

So, are you getting excited yet? Have you worked out what we're going to do? Yes, you've guessed it, we're going to create our own Today screen component and add it to the list.

Why I Think Today Screen Components Are Cool

You might be thinking, "big deal, why should I be getting excited about writing some little hack utility that lists the number of tasks I've got?" Well, I'm going to tell you why, but first, you'll have to start getting into that Gadget Love frame of mind that I tend to spout about after I've had a few pints of Guinness. Sadly, after a few pints, my accent starts to become even less intelligible than normal (remind me to tell you about the "Twelve Bottles of Heineken and the Embarrassing Press Launch incident" some time), and so here are my thoughts in a slightly more sober format. I've left in a few little drunken-type effects for realism.

Let me in! I've lost my keys again! I love you! I think I'm going to be sick! A Pocket PC isn't simply a little computer, it's a little computer that you can carry with you everywhere, and use all the time. Even the smallest, lightest, sexiest new Sony laptop live up to this expectation. A Pocket PC quickly becomes as personal, and as important, as a wallet.

Just like a wallet, a Pocket PC will start to collect important information, contact information, notes, and photographs. Better than a wallet, a Pocket PC will also start to collect Windows Media Format files, movies (if you have a good-sized Compact Flash card), eBooks, and even games.

The point is that everyone wants his or her Pocket PC to look and act in a particular and unique way. Imported leather cases and leopard skin, multifunction belt cases are one approach, and customised Today screens are another.

Back to the Bar

As a slight aside, it's worth looking at the rest of the Today screen before we get coding. Unlike the Palm-size PC screen (remember those?), or in fact, Big Brother desktop Windows, the Pocket PC Today screen has its own unique status/menu bar at the bottom of the screen.

This status bar is not seen in any other applications because it is replaced by a menu bar. So, while it is entirely possible to add a cute little icon to this bar, it simply won't be seen when the user is running anything other than the Today screen. In some ways this is quite a shame, as this part of the screen was a handy place to store often-used programs, especially those of a little, shall we saw, hack-y nature.

If you are desperate to get an icon or something into the user's line of sight no matter what application they are running, you could potentially abuse the title bar at the top of the screen. Unless an application specifically launches itself as full-screen, the title bar can always be seen. There is no official support for adding your own applications to this part of the screen, but I could share a few secrets in a later column if you posted some nice comments (or sent some cash). Several third party programs (WISbar and Gigabar for example) completely overwrite the title bar to add new graphics and utilities. Of course, this kind of practice is entirely unsupported, but such utilities are immensely popular and shouldn't be ignored.

Practical Today Screen Component Programming

What form does a Today screen component actually take? It's nothing more than a DLL file, created in Microsoft eMbedded Visual C++®, copied to the Pocket PC, and referenced from the registry. The process of creating and using the component, therefore, goes a like this:

  1. Write the DLL, paying particular attention to certain Windows messages.
  2. Place the DLL into the Windows/ directory on the Pocket PC.
  3. Insert a new key and some new values into the Pocket PC registry.
  4. Switch on the component from Start/Settings/Today dialog.

There is a little more to it of course, but once you've seen the basic framework of code, you'll quickly and easily get your own components up and running. Sadly, it's not possible to use Microsoft eMbedded Visual Basic® to create these components (suck it up, Larry!).

With only a few minor additions, the component behaves like a typical Win32® application. So we have a WM_Paint section of code, for example, that handles the display. We can assume that we have an application that has given us a small rectangle of screen real estate, 240 pixels wide by a program-defined number of pixels high. If you want your program to support any third party landscape mode utilities, you can't assume the 240 pixel-wide window and should query the system first.

Today components share enough of the standard Windows application features to ensure that they can respond to screen taps. This means that your components can both report information (your new task reporting application, for example), and respond to user actions (tap to display more information on the task). The component can appear like a mini-application, albeit one that is readily available to the user on the desktop.

Code Skeleton

Here's a chunk of code that highlights the important parts, and forms a useful skeleton for your own Today screen component. I've also included the entire project for you to download and use from within eMbedded Visual C++ to make it easy for you to get started.

//
// Example TODAY COMPONENT code.
//
// Simple draws a large, black, rectangular
// lump. It'll get more exciting, honest.

#include "windows.h"
#include <todaycmn.h>
#include <Aygshell.h>

const TCHAR k_szWindowClass[] = TEXT("TodayTest");
HINSTANCE g_hInst = NULL;

// The height, in pixels, of the Today component is
// picked at random. It's gotta be something!

#define MODULE_HEIGHT 42


/*************************************************************************/
/* WndProc for the window                                                */
/*************************************************************************/
LRESULT WINAPI CustomItemWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp)
{
 PAINTSTRUCT ps;
 HDC hdc=NULL;

 // This structure is used to store all kinds
 // of internal Today component information.
 TODAYLISTITEM *ptli2;
 switch(msg)
 {

  // This happens when data changes..
  case: (WM_TODAYCUSTOM_CLEARCACHE):
   break;

  // This happens every two seconds or so.
  case (WM_TODAYCUSTOM_QUERYREFRESHCACHE): 
   ptli2=(struct _TODAYLISTITEM *)wp;

   // This is an important part,
   // so pay attention!
   if (0 == ptli2->cyp)
   {
    // Only return true once, when the
    // height is being set.
    ptli2->cyp = MODULE_HEIGHT;
    return TRUE;
   }
   else
   {
    // Most of the time this branch will occur.
    return FALSE;
   }
   break;

  // Standard Windows Paint message
  case WM_PAINT:
   hdc = BeginPaint(hwnd, &ps);
   // Quick and dirty paint example
   BitBlt(hdc,0,0,240,MODULE_HEIGHT,NULL,0,0,BLACKNESS);
   EndPaint(hwnd, &ps);
   break;

  default:
           break;
    }
    return DefWindowProc(hwnd, msg, wp, lp);
}




/*************************************************************************/
/* Initilize the class                                                   */
/*************************************************************************/
void InitilizeClass(HINSTANCE hinst)
{
    WNDCLASS     wc;
    memset(&wc, 0, sizeof(wc));
    wc.style         = 0;
    wc.lpfnWndProc   = (WNDPROC)CustomItemWndProc;
    wc.hInstance     = hinst;
    wc.hIcon         = NULL;
    wc.hCursor       = NULL;
    wc.hbrBackground = (struct HBRUSH__*)GetStockObject(WHITE_BRUSH);
    wc.lpszClassName = k_szWindowClass;
 UnregisterClass(k_szWindowClass, hinst);
    RegisterClass(&wc);
}


/*************************************************************************/
/* Initilize anything that is required for the DLL.                       */
/*************************************************************************/
BOOL WINAPI DllMain(HANDLE hDLLInst, DWORD fdwReason, LPVOID lpvReserved)
{
    UNREFERENCED_PARAMETER(lpvReserved);
    switch (fdwReason)
    {
    case DLL_PROCESS_ATTACH:
        g_hInst = (struct HINSTANCE__ *)hDLLInst;
        DEBUGREGISTER((HINSTANCE)hDLLInst);
        InitilizeClass((HINSTANCE)hDLLInst);
        break;
    case DLL_PROCESS_DETACH:
        UnregisterClass(k_szWindowClass, (struct HINSTANCE__ *)hDLLInst);
        break;
    }
    return TRUE;
}


// This code is the entry to the Today component DLL:
HWND InitializeCustomItem(TODAYLISTITEM *ptli, HWND hwndParent) 
{
    HWND hWnd;
 if (!ptli->fEnabled)
        return NULL;
    hWnd = CreateWindow (k_szWindowClass, k_szWindowClass, WS_VISIBLE|WS_CHILD, 0, 0, 0, MODULE_HEIGHT,
        hwndParent, NULL, g_hInst, NULL);
    ShowWindow (hWnd, SW_SHOWNORMAL);
    return hWnd;
}

Apart from the .cpp file, you must create an extra file that exports the DLL settings. The .def file is nothing more than a text file that contain the following three lines:

EXPORTS
InitializeCustomItem @ 240 NONAME
CustomItemOptionsDlgProc @ 241 NONAME

Once you create the .def file, make sure to add it to your source files using the menu option Add Files to Folder.

Registry Settings

With our code complete, the DLL can sit in the Windows directory forever, but nothing will happen until it is added to the registry. The Pocket PC registry contains a key called HKEY_LOCAL_MACHINE\Software\Microsoft\Today\Items\ that lists all the currently installed Today screen components. If you want your component to appear in that list on the Settings dialog, you'll need to create a key and then add the following information:

Key Name Type Sample value Purpose
Type DWORD 4 Marks the component as "custom", i.e., you wrote it.
Enabled DWORD 1 1 or 0, specifying if the component is active or not.
Options DWORD 1 1 or 0. Set 1 if there is an Options dialog.
DLL String \windows\todaycomponent.dll Path and name of the DLL comprising the component.

Figure4. Using the development tool's registry editor, add the new key and values to tell the Pocket PC to use your new component.

The easiest way to add the details is to use the registry editor that is included with the Visual eMbedded Toolkit. You can also use a registry editor on the Pocket PC device itself (one of the best is written by Philippe Majerus and is available from http://www.phm.lu/Products/regedit.asp) or add the new keys to the installation routine that you will eventually use to distribute your new killer app.

Once you've entered the new registry details, you can try out the component by going to Start/Settings/Today and ensuring that there is a check mark next to the component name. If the name doesn't appear, make sure you have the registry details correct and the dll is in the right location.

Figure 5. Switch on your component from the Today's settings dialog. You can alter its position in relation to the other components by tapping the Move Up/Move Down buttons. The Options... button will open a dialog that you can use to request settings from the user.

Debugging Tips

When creating Today screen components, you'll soon come across one rather tedious little feature. You'll discover that it's not possible to overwrite the component with a new version because the old one will report that it's still in use. This can make the compile-test-edit-compile-test cycle a chore.

The obvious solution is to switch off the component (from Start/Settings/Today), and then perform a warm reset. Once you re-establish the ActiveSync® connection, the component can be deleted or replaced. Of course, re-establishing the connection takes time and gets boring.

I like to create the replacement Today DLL with a slightly different name (for example, mycomponent2.dll rather than mycomponent1.dll), and then edit the registry to reflect the new component name. Close and reopen the component from the Settings dialog, and the new code is running. You can recycle the names and build up a set of three or four components on the device, but even after the registry editing, this process is a lot quicker than anything involving a reset is.

Next Time…

Next month, we'll use the skeleton code to create a component that provides a useful calculator feature. The calculator will have a skinable interface that will make it easy to change to suit your personal tastes.

Pocket PC Programming Trick

If you like writing small applications and utilities that make your Pocket PC easier to use, then join the club—that's my favorite pastime too. Here's a useful code snippet that brings the Today screen to the front of the display order. This can be useful when assigning a hardware key (use Start/Settings/Buttons to assign the application to a key), or used from within a third-party task utility. Simply add this code

// Find the Today screen and bring it to the front.
HWND top = FindWindow(TEXT("DesktopExplorerWindow"),TEXT("Desktop"));
if (top != NULL)
   SetForegroundWindow(top);

John's Pocket PC Hints

Check out the price of Compact Flash cards at the moment

Sure signs you are getting old: the music in the pop charts is mostly random noise, your jeans are getting tighter around the old waist, and memory prices are dropping faster than drool from your chin in a Best Buy store. The current price of large capacity Compact Flash cards—that is, 128Mb and 256Mb cards—is amazing. In my day, and only a year ago, they were a lot more expensive. Buy now and keep your favorite eBooks and albums of "real music" in WMA format with you all the time.

Get more into that HP Jornada's CF socket

I really like the Hewlett-Packard Jornada Pocket PC. I like the slim metal case and flip-up screen cover. What I don't like is the Compact Flash Type 1 expansion socket. Almost all other Pocket PCs have a Type 2 socket, and they have no problems with massive Microdrive memory cards, chunkier network cards, and other Type 2 only hardware.

Well, good news Jornada owners. A device called the CF Pocket that was mentioned on several Japanese Web sites has reached the Western World. The CF Pocket is a small pouch that slots into the Type 1 socket, and offers a full Type 2 socket in return. I've tested it with a 340-megabyte (MB) Microdrive card and it works perfectly.

The CF Pocket is available from several good Pocket PC accessory stockists, including atek.com and MobilePlanet.

Get ready for wireless LANS

It's getting easier and cheaper to go wireless with your local area network. PC Card (also known as PCMCIA) format IEEE 802.11b cards have been around for quite a while now, but at least two manufactures—DLink and Socket—are launching Compact Flash format versions. This means that Casio and Hewlett-Packard devices should soon be able to join in the fun.

Once you've tried a wireless LAN card on your Pocket PC, you'll never go back. If you are lucky enough to have a broadband (cable or DSL) connection, you can browse the Web at high speed from anywhere in your house, listen to live radio, and watch streaming video, not to mention having speedy downloads and responsive debugging during developing, all without any nasty cables.

 

John Kennedy is a Technical Writer/Programmer in the Visual C++ group by day and leads a secret life as a Pocket PC developer by night.

Larry Roof is a partner at tonked, a firm that specializes in the development of mobile solutions and training. He's the author of Professional Visual Basic Windows CE, available from Wrox Press.

Page view tracker