|
Chapter 15: Extending the Pocket PC continued
Writing a Custom Today Screen ItemThe Today screen is the home page of the Pocket PC. It’s automatically displayed after the system isn’t used for a predetermined period of time. It contains a snapshot of the relevant data from the applications bundled with the Pocket PC. By using a simple DLL, you can extend the Today screen to allow other applications to summarize their data or to allow stand-alone Today screen inserts that provide data only through the Today screen. Figure 15-1 shows the Today screen with five items: the Today title bar, the Owner Info item, the Tasks item, the Inbox item, and the Calendar item.Today screen items are implemented as simple Windows CE DLLs with two predefined entry points. The system finds the extensions by looking under a specific registry key. It then loads the DLL, asks the item its desired height, and asks it to display its data. The Today Control Panel applet allows users to selectively enable and disable individual items as well as set the order of the items on the Today screen. The user can also configure an individual item through the Today Control Panel applet. When the user selects an item from a list of all the Today screen items and taps the Options button, the item’s DLL is loaded and a dialog box is created by using a dialog box procedure exported from the DLL. This dialog box is created using resources stored in the DLL. Figure 15-1 The Pocket PC Today screen Creating a Today Screen Item DLLThe requirements for a Today screen item DLL start with an exported entry point, InitializeCustomItem, which must be exported as ordinal 240. The DLL can also optionally support a configuration dialog box. If it does, the DLL must export another entry point, CustomItemOptionsDlgProc, at ordinal 241, which is used as the dialog box procedure for the options dialog. In addition, the resource for the options dialog must be included in the DLL’s resource and have a resource ID of ID_TODAY_CUSTOM.The InitializeCustomItem function is prototyped as
HWND APIENTRY InitializeCustomItem (TODAYLISTITEM *ptli, HWND hwndParent); The first parameter is a pointer to a TODAYLISTITEM structure; the second parameter is the handle of a window that will be the parent of the item window created by the extension. Because the TODAYLISTITEM structure is used throughout the Today screen interface, this is as good a place as any to describe it. Many of the fields in this structure might not be useful or even relevant in this call. However, the structure tends to be passed back to the DLL on almost every call, so most of the fields are used at some time in the life of the DLL. The structure is defined as
typedef struct _TODAYLISTITEM {When InitializeCustomItem is called, the szName field is filled with the name of the registry key that identified the item. This name is handy for finding the item’s registry key to retrieve custom data. The second field is tlit, a TODAYLISTITEMTYPE enumeration that defines the type of extension. For custom extensions this field will always be tlitCustom. The dwOrder field will be set to the order index of this item. The cyp field contains the height of the item in pixels. Items are ordered from the lowest to the highest value starting at the top of the Today screen. The user controls the order through the Control Panel applet. For most situations, an extension’s order in the Today window shouldn’t affect the extension’s behavior. The fEnabled field indicates whether the user has enabled your Today item in the Control Panel. This field should be queried when InitializeCustomItem is called; if it is 0, you should return immediately with a return code of 0. The fOptions flag reflects whether the Today item has an options dialog. This flag is taken from the registry entry for this item. Let’s skip the grfFlags field for a moment. The szDLLPath field contains the filename of the DLL that contains the code for the item. The hinstDLL field is the DLL’s instance handle. The hwndCustom field will contain the handle of the item’s child window when this structure is passed after the item’s child window has been created. The Today screen item manager uses the fSizeOnDraw field internally. The last two fields, prgbCachedData and cbCachedData, along with the grfFlags field, allow the DLL to store, or cache, custom data about the state of its window and the data it is displaying. The goal here is to prevent the item from having to query a file or database every time the Today screen is asked to repaint itself. The grfFlags field can be set to anything the DLL requires. Likewise, if the DLL needs to store additional data, a memory block can be allocated. A pointer to the memory block is saved in prgbCachedData, and the size of the memory block is saved in cbCachedData. Since these values are passed back to the DLL on a regular basis, these fields free the DLL from having to store data internally in statically defined structures. Creating the Item Window When InitializeCustomItem is called, the DLL should create its child window that will display the data for that item. The window should be a child window with its parent set to the window handle passed in the hwndParent parameter. The function should return the handle to the child window if the initialization was successful, or 0 otherwise. Of course, to create a window, you will first need to register a class for that window. The class registration can take place either during the processing of the InitializeCustomItem call or during the PROCESS_ATTACH notification to DllMain when the DLL is loaded. If the registration is performed during the InitializeCustomItem call, be sure not to return failure from the function if the call to RegisterClass fails. Because InitializeCustomItem is called more than once, the second call to register the class will fail if the DLL attempts to repeat the class registration. The DLL should also be designed to unregister the window class when the DLL is unloaded. This design feature is quite helpful for debugging purposes, when the DLL will change as the code develops. The Item Window Once the item’s window is created, the Today screen will send a custom message, WM_TODAYCUSTOM_QUERYREFRESHCACHE, to the child window. When the message is sent, the wParam parameter points to the TODAYLISTITEM structure that was passed in the call to InitializeCustomItem. The message is sent to ask the item if the data it is presenting to the user has changed and therefore the window needs updating. If so, the window should set the cyp field of the TODAYLISTITEM structure to the height in pixels for the item window. The window should return TRUE for the message. If no update is necessary, the window should respond to the message with FALSE. It is important that the item window return TRUE only when necessary, since returning TRUE causes the Today screen to repaint itself. Having this happen too oftenespecially when nothing on the screen changesdistracts the user and wastes power. The item shouldn’t draw in its window during the handling of the WM_TODAYCUSTOM_QUERYREFRESHCACHE message. If the data changes and the item returns TRUE, the item’s window will be invalidated by the item manager, causing a WM_PAINT message to be sent to the item window, which is where the window should be redrawn. The WM_TODAYCUSTOM_QUERYREFRESHCACHE message is sent to the item’s window every few seconds, allowing the item to check whether it needs to modify the currently displayed data. Since the item has a chance to modify the cyp field, this is also the place where the item can ask to be resized to a taller or shorter window. The width of the window will be the full width of the Pocket PC screen minus the width of the scroll bar if present. Interacting with the User The custom item interacts with the user by painting its data onto its window in response to WM_PAINT messages. Because the custom item is a window, it also receives any mouse messages. Given that the user interface guidelines recommend a single click for most actions, the typical thing to do is monitor for a WM_LBUTTONUP event and provide a default action. For example, the item might launch the application that can edit the data the item shows. Because the item is simply a child window of the Today screen, it can do almost anything a window can do, with these limitations: The Today screen controls the size and position of the item child window, so the item shouldn’t try to move or size itself. Also, the Today screen is designed to scroll if more items are being displayed than can fit on the screen. Because of this feature, the item manager can move your child window at any time. Unloading the Custom Item When the Today screen item manager needs to completely refresh the items on the Today screen, it notifies each window by sending a WM_TODAYCUSTOM_CLEARCACHE message. Here again, the wParam parameter points to the item’s TODAYLISTITEM structure, allowing the individual items to free the memory they have allocated during the life of the item. Generally, this means freeing the data block pointed to by the prgbCachedData field if the item had previously allocated such a block of data. The Options Dialog Today items must implement their options dialog in a rather strange way. The DLL doesn’t simply export a function that the Today item manager could call to instruct the item to display an options dialog. Instead, the DLL is required to export a specific function, the Options dialog box procedure, and provide in its resource block a dialog box template with a specific ID number. With a pointer to a dialog procedure and a dialog template, the item manager can call CreateDialog itself. The dialog box procedure provided by the item should conform to Pocket PC user interface guidelines and call SHInitDialog to make itself full screen. In addition, the documentation suggests that the Options dialog box be written to look like the Today screen Control Panel applet, with blue header text and a separator line above whatever dialog controls you see fit to use. The example program at the end of this section has an Options dialog box that conforms to these suggestions. The configuration data should be stored in the registry so that the item window can query it when the Today screen loads the item. Registering the Custom Item The Today screen locates the custom items by looking in the registry for a list of items. The registry key that contains the list is [HKEY_LOCAL_MACHINE]\Software\Microsoft\Today\Items. Each custom Today screen item should create a subkey under the key listed above. This subkey name will be the name shown to the user in the Today screen configuration dialog, so it must be localized for the appropriate language. Under the item’s subkey, a number of values must be set. The values are
The Today screen looks at these registry entries when it loads the items on the Today screen, which happens when the system boots and when the user closes the Today screen Control Panel applet. Debugging a Custom Item One of the problems with developing a Today screen item is how to force the Today screen to unload a custom item so that a developer can download a revised copy of that item. When the Today screen starts, it loads all the DLLs listed under the Items key previously described. The DLLs remain loaded even if the user doesn’t enable them. It’s difficult to update a registered Today screen item because a DLL can’t be overwritten until the Today screen unloads that DLL. In my experience, the best way to force the Today screen to unload an item is to open a registry editor on the Pocket PC or use the Windows CE Remote Registry Editor and change the name of the DLL listed under the DLL value for your item. You then open the Today screen Control Panel and enable or disable another item and close the Control Panel. This series of actions causes the Today screen to free all DLLs and reload the ones listed in the registry. Because you have just changed the DLL value to some filename that doesn’t exist, the Today screen can’t load that DLL, thereby allowing Microsoft eMbedded Visual C++ to download a new copy.
The PowerBar Custom Today Screen ItemThe PowerBar example is a Today screen extension that displays the status of the battery as a bar running across the item window. PowerBar includes an options dialog that conforms to the look and feel of the options dialogs of the other Today screen items. Using the options dialog, you can change the height of the PowerBar item from a wide bar that displays an icon and a text display of the battery state to a thin 5-pixel bar that takes up very little room on your Today screen. Tapping the PowerBar item launches the Power Control Panel applet.To install PowerBar, you need to edit the Pocket PC registry to add an entry for PowerBar under [HKEY_LOCAL_MACHINE]\Software\Microsoft\Today\Items, as I explained earlier. For the DLL name, use \Windows\Powerbar.dll. Figure 152 shows the Today screen with the PowerBar custom item. Figure 15-3 shows the PowerBar source code. Figure 15-2 The Today screen with the PowerBar custom item displayed This example has an additional source code file, PowerBar.def. Def files provide a method for defining specific ordinal values for exported functions. In the case of Today screen items, the exported function InitializeCustomItem and the options dialog box procedure must be assigned ordinals 240 and 241, respectively. Figure 15-3 The PowerBar example PowerBar.def
EXPORTS PowerBar.rc
//====================================================================== PowerBar.h
//======================================================================
// Generic defines and data types PowerBar.c
//====================================================================
// Copyright (C) 2001 Douglas Boling
//----------------------------------------------------------------------
return DefWindowProc (hWnd, wMsg, wParam, lParam);
// If the battery value has changed since the last check,
PAINTSTRUCT ps;
else
lf.lfPitchAndFamily = tm.tmPitchAndFamily;
case WM_CTLCOLORSTATIC:
// Enumerate the item list until The code that displays the Today screen item is not complex. In the InitializeCustomItem call, PowerBar registers the window class and creates the child window. In the window procedure, the code that handles the WM_TODAYCUSTOM_QUERYREFRESHCACHE message sets the cyp field of the TODAYLISTITEM structure to the proper height, which is configurable through the options dialog. The routine then checks the power status of the system by calling GetSystemPowerStatusEx. If the battery level has changed since the last check, the routine returns TRUE, forcing the Today screen to redraw the item. In the WM_PAINT handler, the bar is drawn across the window using the rectangle function. Depending on the height of the window, the icon is drawn and the power level is printed in the window. The options dialog procedure, CustomItemOptionsDlgProc, goes to great lengths to provide the proper look to the dialog box. To this end, a custom font, 8.5-point Tahoma, is used to display the top line of text in the dialog box. In addition, this line of text is displayed in blue and a solid line is drawn 23 pixels below the top of the dialog. These customizations match the look of the Today items dialog. The font is created in the WM_INITDIALOG message. To override the drawing of the top line of text, the dialog procedure fields the WM_CTLCOLORSTATIC message. The following code shows howafter checking which control is being drawnthe dialog box procedure sets the text color and the font so that the text is displayed with the customized look.
case WM_CTLCOLORSTATIC: The Today screen is an example of the extensibility of the Pocket PC shell. Applications that provide an additional Today screen item to summarize their data provide that extra bit of integration that users appreciate.
Last Updated: Saturday, July 7, 2001 | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||