Discussing the nuts and bolts of software development

Thursday, May 10, 2007

 

Why, that's just SNAPI!

Windows Mobile 5 is the new version of Windows CE 5.0 that is targeted at the Windows mobile market. It is the underpinnings of both the Pocket PC and Smartphone editions.

Windows Mobile 5 comes packed with some new (native) features and APIs such as:
Perhaps I'm simply too much of a geek, but SNAPI is just a cool name. Go ahead, say it out loud. "SNAPI". Now say it with a Sean Connery voice. "SNAPI". Damn cool.

SNAPI is a great improvement to Windows Mobile, long overdue. Basically SNAPI is a registry notification system. You receive events when keys or values you are watching are changed in the registry. You can use SNAPI on any sub-key or value in the registry. However there are some pre-defined helpers specifically related to the state of the device. For a full list see snapi.h.

In my last Windows Mobile project, I used SNAPI for many things, some of which I will get into in later posts, but perhaps the easiest use was to register for the battery state notifications.

Some devices show the battery strength indicator in the shell notification area of the screen and some show it only on the "Today" screen; we had a requirement to show the battery strength on the application's main screen.

This is a common requirement, in past non-WM5 projects, we had to set up a thread and to poll the value, update the screen, then repeat. Not hard, just tedious.

In WM5 however, all we needed to do was to register to that notification. Registering is easy:
// Battery strength
NOTIFICATIONCONDITION nc = { 0 };
nc.ctComparisonType = REG_CT_ANYCHANGE;
nc.dwMask = SN_POWERBATTERYSTRENGTH_BITMASK;
nc.TargetValue.dw = 0; // ignored for REG_CT_ANYCHANGE

HREGNOTIFY regNotify;

HRESULT hr = ::RegistryNotifyCallback(
SN_POWERBATTERYSTRENGTH_ROOT,
SN_POWERBATTERYSTRENGTH_PATH,
SN_POWERBATTERYSTRENGTH_VALUE,
onBatteryStrengthChangedCallback,
0,
&nc,
&regNotify );

// save hr if successful somewhere for later use

RegistryNotifyCallback registers a transient notification request that will be used to notify the caller via the specified callback when the value of the sub-key changes. Transient simply means that the registration to the registry notification will not survive a device reset.

It's important to note that when notified of changes via the callback, the callback is executed on a private thread separate from the one called RegistryNotifyCallback.

If the value or the key does not exist at time of registration, the caller will be notified when the value or key is added.

The callback has to have the following signature:
void onBatteryStrengthChangedCallback(
HREGNOTIFY hNotify,
DWORD dwUserData,
const PBYTE pData,
const UINT cbData )

Now that we're registered, the supplied callback will be called whenever the battery strength changes. A sample implementation of the call back could be as follows:
// pData contains the new value for SN_POWERBATTERYSTRENGTH_VALUE.
DWORD batteryStrength;
batteryStrength = (*(DWORD*) pData);
batteryStrength = ( batteryStrength & SN_POWERBATTERYSTRENGTH_BITMASK ) >> 16;

// update the screen
...

See, very simple. When don't want to get the notifications anymore, just call:
// hr was what was returned from registering successfully to the notification.
::RegistryCloseNotification( regNotify );

This API has to be called to stop receiving the notification and to close the handle.

There are however, some caveats with using this API: how often the value changes in the registry is dependent on the device. Some devices only update the value when the actual strength hits a predefined boundary, such as 75%, 50%, or 25%. The value also gets changed when you plug in the device to be charged, and then unplugged. On some devices I see the strength go briefly from 100% to 0% when un-cradled.

As you can see SNAPI provides alot of functionality, and is a pretty flexible API. In future posts I hope to explore this API in further detail.

Labels: , , ,


Comments: Post a Comment



<< Home

This page is powered by Blogger. Isn't yours?