MobileCreating Custom Today Screen Items

Creating Custom Today Screen Items

Developer.com content and product recommendations are editorially independent. We may make money when you click on links to our partners. Learn More.

What is the Today Plug-In?

You obviously know what the Today screen is. You see it every time with the Microsoft logo (or whatever picture you’ve put beneath). And, you definitely won’t be surprised to know that the Today custom component is just a DLL. The only additional fact you should know about it is that such a DLL should export two predefined functions with the given ordinal number:

; Contents of .DEF file
LIBRARY CustomItem

EXPORTS
InitializeCustomItem        @240    NONAME
CustomItemOptionsDlgProc    @241    NONAME

Being more precise, only the first function is a must. The second one is required if you want to provide an Options dialog for your component. Before you will dig in into code samples, let me highlight a couple of trivial things regarding Today components.

First, your DLL will be loaded at startup by the shell and won’t be released until you turn off or reset the device. Unchecking the component in Today’s settings panel does not help you at all. Thus, it’s pretty hard to debug it. To release the problematic DLL, you should manually change the Registry settings and then reset the PDA.

The next thing to be considered is a place on the screen covered by your component. Due to lack of screen size, you should produce a relatively small-dimensioned GUI. Moreover, if there are too many Today items simultaneously presented on the screen, Windows CE adds a scroll bar, so the actual screen width will be smaller that the standard 240 pixels.

Installing Your Custom Today Item

Your component should be registered to let the OS know about its existence. Literally, it means to make some changes in the Tegistry. You can do it either by preparing a .cab file or developing your own application to update the CE registry. Below is the .inf-file section to command the installer to make the Registry changes:

[Registry.All]
; DWORD, Custom Items must always have Type = 4
HKLM,SoftwareMicrosoftTodayItemsCustomItem,Type,0x00010001,4
; DWORD
HKLM,SoftwareMicrosoftTodayItemsCustomItem,Enabled,0x00010001,1
; DWORD, If you're providing "Options" dialog, set this value to 1
HKLM,SoftwareMicrosoftTodayItemsCustomItem,Options,0x00010001,0
; STRING, This value keeps path to your DLL
HKLM,SoftwareMicrosoftTodayItemsCustomItem,DLL,0x00000000,
     "CustomItem.dll"
; DWORD, This value allows getting notifications by your component,
         set it to 2
HKLM,SoftwareMicrosoftTodayItemsCustomItem,Selectability,
     0x00010001,2

The following table gives you a short explanations of the Registry values:

Value Name and Type Description
DWORD: Type Custom Items must have Type = 4
DWORD: Enabled 0 or 1; 1 causes Today panel to show your component; nevertheless, the user can control it via the Today applet in the Control Panel
DWORD: Options if equals 1, the “Options” button in the Today applet will be enabled
SZ: DLL Pull path to your component
DWORD : Selectability New feature in Win Mobile 2003 SE; allows receiving additional notifications
Values are used as follows:

  • 0 or does not exist—component cannot be selected at all
  • 1—selections are manages automatically. In other words, your component will receive messages like WM_LBUTTONXXX
  • 2—the Today screen will send notification messages to your component when the user sets/releases focus or presses navigation keys

In case you’ll want to develop your own registration program, following are a few tips of doing it more easily:

To Install

  • Place the component DLL in the desired folder
  • Add appropriate values to the Registry (see above)
  • Send a broadcast message to cause the OS to accept changes:
    SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0xF2, 0)

To Uninstall

  • Remove the key you created during Install (HKLMSOFTWAREMicrosoftTodayItemsYOURCOMPONENT)
  • Send a broadcast message to cause the OS to accept changes:
    SendMessage(HWND_BROADCAST, WM_WININICHANGE, 0xF2, 0);
  • Wait to let the OS release your component DLL
  • Delete the DLL

As you have told learned, your DLL will export two functions: InitializeCustomItem and optionally CustomItemOptionsDlgProc. In most cases, you’ll want to draw one or more icons or images. An important thing to be noted is that you should load all required resources at attaching the DLL and then release them when you exit:

HICON            g_hIcon;
HINSTANCE        g_hInst;
HWND             g_hWnd;
...
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call,
                       LPVOID lpReserved)
{
   switch (ul_reason_for_call)
   {
   case DLL_PROCESS_ATTACH:

      // The DLL is being loaded for the first time by a given process.
      // Perform per-process initialization here. If the initialization
      // is successful, return TRUE; if unsuccessful, return FALSE.
      g_hInst = (HINSTANCE)hModule;

      //load the icon
      g_hIcon = (HICON)LoadImage(g_hInst,MAKEINTRESOURCE(IDI_DISPLAYICON),
                                 IMAGE_ICON,16,16,LR_DEFAULTCOLOR );

      //intialize the application class, and set the global window handle
      UnregisterClass((LPCTSTR)LoadString
                      (g_hInst, IDS_CUSTOM_ITEM_APPNAME,0,0), g_hInst);

      // Proceed component initialization
        InitilizeComponent();

      g_hWnd = 0;

      break;

   case DLL_PROCESS_DETACH:
      // The DLL is being unloaded by a given process. Do any
      // per-process clean up here, such as undoing what was done in
      // DLL_PROCESS_ATTACH. The return value is ignored.

      DestroyIcon(g_hIcon);

      UnregisterClass((LPCTSTR)LoadString
                      (g_hInst, IDS_TODAY_STORAGE_APPNAME,0,0), g_hInst);
      g_hInst = NULL;
      break;
   }

   return TRUE;
}

InitializeComponent simply creates and registers a window class for your custom Today item. The shell will call the InitializeCustomItem function when it attempts to create it initially. This function is responsible for all initialization procedures, windows creation, and so forth. Here, you actually initialize all your internal stuff. Below some sample implementation is presented:

HWND InitializeCustomItem(TODAYLISTITEM *ptli, HWND hwndParent)
{
   LPCTSTR appName = (LPCTSTR)LoadString
                     (g_hInst,IDS_TODAY_STORAGE_APPNAME,0,0);

   //create a new window
   g_hWnd = CreateWindow(appName,appName,WS_VISIBLE | WS_CHILD,
      CW_USEDEFAULT,CW_USEDEFAULT,240,0,hwndParent, NULL, g_hInst, NULL) ;

   // create the storage space progress bar
   g_hBatteryProgressBar =
      CreateWindow(PROGRESS_CLASS, TEXT("Battery Progress Bar"),
      WS_CHILD | PBS_SMOOTH, CW_USEDEFAULT,CW_USEDEFAULT,
      CW_USEDEFAULT, CW_USEDEFAULT,g_hWnd, NULL, g_hInst, NULL);
   SendMessage(g_hBatteryProgressBar,PBM_SETSTEP,1,NULL);

   // create the program memory progress bar
   g_hProgramProgressBar =
      CreateWindow(PROGRESS_CLASS, TEXT("Program Progress Bar"),
      WS_CHILD | PBS_SMOOTH, CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT,
      CW_USEDEFAULT,g_hWnd, NULL, g_hInst, NULL);
   SendMessage(g_hProgramProgressBar,PBM_SETSTEP,1,NULL);

   // create the storage space progress bar
   g_hStorageProgressBar =
      CreateWindow(TRACKBAR_CLASS, TEXT("Storage Track Bar"),
      WS_CHILD | TBS_AUTOTICKS | TBS_BOTTOM,
      CW_USEDEFAULT,CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
      g_hWnd, NULL, g_hInst, NULL);
   SendMessage(g_hStorageProgressBar, TBM_SETRANGE, 1,
               MAKELPARAM(0,100));

   // attach our winproc to the newly created window
   SetWindowLong(g_hWnd, GWL_WNDPROC, (LONG) WndProc);

   //display the window
   ShowWindow (g_hWnd, SW_SHOWNORMAL);
   UpdateWindow (g_hWnd) ;

   return g_hWnd;
}

In your sample, you will implement an informational panel to show different, useful system info:

You can see similar implementation; for example, on a HP iPaq 2410. For simplicity, you won’t deal with the options dialog. So, coming back to the above snippet, InitializeCustomItem makes a ‘black job’ of component initialization. Pay attention that it doesn’t paint anything. All forthcoming messages will be handled in WndProc.

Processing Window Messages

The window procedure of your custom Today item will handle all Windows messages. Most of them just pass to the default handler. You will be interested in processing the following messages:

  • WM_TODAYCUSTOM_QUERYREFRESHCACHE
  • WM_TODAYCUSTOM_CLEARCACHE
  • WM_TODAYCUSTOM_RECEIVEDSELECTION
  • WM_TODAYCUSTOM_LOSTSELECTION
  • WM_TODAYCUSTOM_USERNAVIGATION
  • WM_TODAYCUSTOM_ACTION
  • TODAYM_TOOKSELECTION
  • WM_LBUTTONUP
  • WM_PAINT
  • WM_ERASEBKGND
  • WM_DESTROY

Start from the WM_TODAYCUSTOM_QUERYREFRESHCACHE message. It will be sent to your component to determine whether your data has been updated. So, that’s often a good place for requerying your data. Your sample component simply obtains new data values there. Remember that you should return TRUE if the component needs to be updated, or FALSE otherwise.

WM_TODAYCUSTOM_CLEARCACHE is sent to the component’s windows when it is about to be unloaded. Here, you can release all resources that your component might use during its lifetime.

Now, here’s an overview of newly introduced notification messages, which are controlled by the Selectability value in the Registry. Below, you’ll find short explanations on each message. I’d like just remind you that Selectability should be equal to 2 to use and advantage most of these messages.

In the sample project, which is based on the Pocket PC 2003 SDK sample MemWatcher, you will use some of the notifications above. Even though your test project will not implement all the nice-to-have features, you’ll get the general route of coding.

Processing ‘Mouse’ Events

When the user clicks on your custom component, WinProc will receive WM_LBUTTONXXX messages. You can process them and conduct specific actions in response to clicks. The sample project simply recognizes to which control area the click belongs, and responds by calling different Control Panel applets:

case WM_LBUTTONUP:
   {
      RECT rcBattery;
      SetRect(&rcBattery,20,4,89,30);
      RECT rcMem;
      SetRect(&rcMem,90,4,150,30);
      RECT rcStorage;
      SetRect(&rcStorage,160,4,220,30);
      POINT point;
      point.x = LOWORD(lParam);
      point.y = HIWORD(lParam);

      PROCESS_INFORMATION pi;
      if (PtInRect(&rcBattery, point))
         ::CreateProcess(_T("Windowsctlpnl.exe"),
                         _T("cplmain.cpl,3"),
            NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi);
      else if (PtInRect(&rcMem, point))
         ::CreateProcess(_T("Windowsctlpnl.exe"),
                         _T("cplmain.cpl,4"),
            NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi);
      else if (PtInRect(&rcStorage, point))
         ::CreateProcess(_T("Windowsctlpnl.exe"),
                         _T("cplmain.cpl,4,1"),
            NULL, NULL, FALSE, 0, NULL, NULL, NULL, &pi);
      else
         MessageBox(NULL, TEXT("Detected Screen Tap!"),
                   TEXT("Custom Today Item:"), MB_OK);
   }
   break;

Similar behavior also is implemented for navigation buttons.

Conclusion

I hope this article has convinced you that creating custom Today items is kind of fun. You’re set up well, having the plug-in’s WinProc at hand to process all Windows messages. Besides, the Today API on Windows Mobile 2003 SE provides you with some additions that give you new features. With a relatively small effort, you’re ready to create cool and powerful mobile applications.

Download

Download the accompanying code’s zip file here.

About the Author

Alex Gusev started to play with mainframes t the end of the 1980s, using Pascal and REXX, but soon switched to C/C++ and Java on different platforms. When mobile PDAs seriously rose their heads in the IT market, Alex did it too. Now, he works at an international retail software company as a team leader of the Mobile R department, making programmers’ lives in the mobile jungles a little bit simpler.

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Latest Posts

Related Stories