Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
4/7/2010

Nicolas Guibourgé, Microsoft Corporation

February 2007

Summary

Compare the architectures of the Today screen plug-in (for Pocket PCs) and the Home screen plug-in (for Smartphones). This article also gives advice and samples to efficiently design these plug-ins. This article assumes that you have a basic understanding about the Microsoft® Windows® CE operating system, programming concepts, C++ language, and COM. (11 printed pages)

Download code sample from the Microsoft Download Center.

Applies To

Microsoft Windows Mobile®–based Pocket PCsWindows Mobile–based Smartphones

Introduction

This article is divided into three sections: How It Works, How to Optimize, and Samples. The first section explains the architecture in the Today Screen plug-in and Home Screen plug-in. The second section discusses best practices and optimizations, and the third section provides some code samples.

How it Works

This section is divided into two parts: Today Screen, which describes the Today Screen plug-in architecture, and Home Screen, which describes the Home Screen plug-in architecture.

Today Screen

This section discusses the static organization, process and thread architecture, and initialization of a Today Screen plug-in. It is also important to remember that a Today Screen plug-in only targets Pocket PCs.

Static Organization

A Todayscreen plug-in is a child window of the Todayscreen. A Todayscreen plug-in is a dynamic-link library (DLL) that exports the InitializeCustomItemfunction and has its own window procedure. The Todayscreen application (Shell32.exe) dynamically loads the plug-in by means of the LoadLibraryfunctions. You can enable a Todayscreen plug-in by using the settings or the means of registry keys.

Process and Thread Architecture

A Todayscreen plug-in runs in the context of the Shell32 process. It is hosted by the Todayscreen thread that creates the Todayscreen and initializes the plug-ins by calling the InitializeCustomItemfunction, as shown in Figure 1.

Figure 1. Today screen process and thread architecture

Plug-in Interface

A Todayscreen plug-in is simple to write. The plug-in has to do the following:

  • Export one entry point, which returns the window handle of the plug-in window: the InitializeCustomItemfunction. This function is exported by using an ordinal number. The Shell32 process uses this ordinal number to get a pointer to this function by using LoadLibraryand GetProcAddressfunctions.

  • Manage the following specific messages in its window procedure (in addition to the standard messages, such as WM_PAINT):

  • WM_TODAYCUSTOM_CLEARCACHE

  • WM_TODAYCUSTOM_QUERYREFRESHCACHE

Plug-in Initialization

The Shell32 process initiates a plug-in initialization at boot time or each time the user changes the Todayscreen items list on the Pocket PC's settings. The Shell32 process:

  1. Loads a custom plug-in DLL if the DLL is not already loaded. (The DLL's DllMain is then called).

  2. Calls the InitializeCustomItemfunction that must return the plug-in’s window handle.

  3. Sends the WM_TODAYCUSTOM_CLEARCACHE message to the plug-in.

  4. Sends the WM_TODAYCUSTOM_QUERYREFRESHCACHE message to the plug-in. The plug-in must indicate its height and return TRUE; otherwise, the plug-in will not be displayed.

Home Screen

This section discusses the static organization, process and thread architecture, and initialization of a Home Screen plug-in. It is also important to remember that a Home Screen plug-in only targets Smartphones.

Static Organization

A Homescreen plug-in does not have any windows; more accurately, it does not own a window—it only draws in a rectangle. The Home process, which hosts the Homescreen plug-in, indicates the rectangle that has to be drawn.

A Homescreen plug-in is a Component Object Model (COM) object that implements the IHomePluginand IPersistStreaminterfaces. The Home process loads a plug-in by using a class factory mechanism.

The Home process uses XML files to get the list of the plug-ins that it must load. Each plug-in is identified by its GUID in the XML file. The GUID is the one that is associated with the COM object that contains the plug-in and that has been registered upon the plug-in installation.

Process and Thread Architecture

A Homescreen plug-in runs in the context of the Home process. It is hosted by the Homescreen thread that hosts the window procedure, as shown in Figure 2. A plug-in does not receive any Windows message because it does not create a window neither use a window procedure. The Homeprocess sends events such as PE_PAINT or PE_KEYDOWN to its plug-in by calling the IHomePlugin::OnEventinterface of the plug-in. The Home process is the only application that can send PE_ events to plug-ins.

Figure 2. Home screen process and thread architecture

Plug-in Interface

Writing a Homescreen plug-in is more complicated than writing a Todayscreen plug-in because the class factory and COM interface infrastructure need to be coded. However, it is possible to isolate the class factory and COM interface infrastructure and to focus on the drawing (for more information, see this article's download code sample ). In such a design, the code that manages the drawing is very similar to a Todayscreen plug-in. The plug-in code must initialize itself using the IHomePlugin::Initializeand IPersistStream::Loadmethods, and it must manage events using the IHomePlugin::OnEventinterface, which replaces the window procedure of a Todayscreen plug-in.

Plug-in Initialization

A Homescreen plug-in performs a two-step initialization process:

  1. When you select a Homescreen layout that contains the plug-in, the Homescreen application (Home.exe):

    • Loads the plug-in's DLL and creates the plug-in instance by using the standard COM object creation technique of calling the DllGetClassObjectfunction and the IClassFactory::CreateInstanceinterface method.

    • Initializes the plug-in by calling the IHomePlugin::Initializeinterface method. This interface provides access to the XML file that contains the Homescreen layout by means of its parameters.

    • Persists the plug-in data by calling the IPersistStream::Saveinterface method.

    • Unloads the plug-in DLL.

  2. When the Smartphone boots or just after the user selects a new Home screen layout, the Homescreen application (Home.exe) does the following:

    • Loads the DLL and creates the plug-in instance by calling the DllGetClassObjectfunction and the IClassFactory::CreateInstanceinterface.

    • Loads the plug-in data that have been persisted by calling the IPersistStream::Loadinterface.

After the plug-ins initialize, the Home process draws them by calling the IHomePlugin::OnEventinterface method. This interface and other standard interfaces are used as long as the plug-in is running. When the user turns off the device or when the user selects another layout that does not contain the plug-in, the plug-in is released and its DLL is unloaded by using the standard COM technique of calling DLLCanUnloadNow. However, the DLL is not immediately unloaded after the DllCanUnloadNowfunction returns S_OK. The Homescreen application waits several minutes before unloading it.

The first step of the initialization gives the developer the opportunity to save the initial data retrieved from the XML file in a format that is faster to manipulate. The second step is done each time the plug-in is loaded. The IPersistStreaminterface saves the data during the first step and reads the data during the second step.

How to Optimize

This section is divided into five parts: Data Flow, Power Management, Display Management, Memory Consumption, and Initialization. The subsections in each of these parts are subjects that software designers should take care of when they design a Today screen or a Home screen plug-in.

Data Flow

This section presents two common rules about data flow. These rules are:

  • Separate data from drawing.

  • Use notification instead of polling.

This section also explains how you can manage notification.

Separate Data from Drawing

Retrieving data can be slow or even very, very slow, for example, filtering all appointments of the current day.

The Shell32 or Home application draws its plug-ins one after another. For that purpose, it goes through its plug-in list and sends either a WM_PAINT message or a PE_PAINT message to each of them. If a plug-in takes time to retrieve or compute the data it needs when it receives WM_PAINT or PE_PAINT, it delays its own display and the display of the plug-ins that are following it in the list.

A Today screen or Home screen plug-in should retrieve and compute the data it needs in a thread that is different than the one that manages the drawing—even though this technique is more complicated than having data management and drawing done upon WM_PAINT or PE_PAINT message reception.

Use Notification Instead of Polling

Using notification instead of polling is a good rule that saves the CPU time, the battery energy, and also increases the plug-in’s responsiveness, and, in many cases, the responsiveness of the whole device.

To illustrate, assume that you should design a plug-in that displays the number of appointments the device user has during the current week. To always be up to date, this plug-in can do the following:

  • Monitors the agenda database each second and checks if there is a new appointment or if an appointment has been deleted or moved. Then, it updates the appointment counter accordingly. When you use this technique, the plug-in consumes CPU time and battery energy each second to check if its appointment counter needs to be changed.

  • Waits for the notification of new appointment, appointment change, or a deleted appointment from the agenda application and changes its counter accordingly. In such a case, CPU time and battery energy only is consumed when necessary.

Manage Notifications

There are several ways of handling notifications. The design must guarantee that data retrieval will not delay the plug-in’s drawing. In most cases, this means that the data will be retrieved and computed in another thread than the one that draws the plug-in.

An obvious design would be to implement a worker thread that receives notification, computes data, and then calls the IHomePluginEnvironment::InvalidatePlugininterface (Home screen plug-in) or the InvalidateRectmethod (Today screen plug-in) to initiate a new drawing of the plug-in as shown in Figure 3. The Home or Shell32 application consequently sends a PE_PAINT message or WM_PAINT message (respectively) to the plug-in.

Figure 3. Worker thread

A notification can consist of a callback procedure, an event, a message queue, or a Windows message. The state and notification broker, which sends notifications of system information in a Windows Mobile 5.0 system, can send notifications by using all of those mechanisms, whereas the Pocket Outlook® Object Model (POOM) only offers notification by means of Windows messages, such as the PIM_ITEM_* message from the calendar. The Todayscreen plug-in can easily manage this kind of notification by using its window procedure. However, you should not forget that the window procedure of a specific plug-in is executed in the context of the thread that also executes the window procedure of each activated plug-ins. Therefore, a good design would manage the data from the agenda in a worker thread that the window procedure uses upon reception of the Windows message notification.

Developers cannot use the Windows message design for Homescreen plug-ins without some extra programming because a Homescreen plug-in does not host any windows and, therefore, any window procedures. To handle the Windows message notification, a Homescreen plug-in must implement a listener window that manages the Windows message in its window procedure. A listener window is simply a window that is not displayed and that does not draw anything. The window procedure of this listener window manages the Windows message notification. This concept is illustrated in the Notification sample in this article's download code sample . When implementing such a design, you should not forget that the window procedure is executed in the context of the thread that has created it. You must implement one of the following two designs:

  • Have a listener window that forwards notifications to a worker thread, which manages the data and calls the IHomePluginEnvironment::InvalidatePlugininterface to initiate the drawing of the plug-in.

  • Create a worker thread that creates the listener window and hosts the message loop. The window procedure handles the message, manages the data, and then calls the IHomePluginEnvironment::InvalidatePlugininterface to initiate the drawing of the plug-in.

Power Management

Because power is a restricted resource on Pocket PCs and Smartphones, it is essential to conserve it. A Todayscreen or a Homescreen plug-in must limit the amount of power it uses and only redraw if the display is on or if the information is important enough, for example, a reminder. In the case of Smartphones, you can use the GetSystemPowerStateAPI to determine whether the display is turned on, as the following code example shows.

Copy Code
	DWORD PwrFlag, NameLength ;
	TCHAR StateName[64] = { 0 } ;
	GetSystemPowerState(StateName, NameLength, &PwrFlag) ;
	if(POWER_STATE_ON != PwrFlag)
		InvalidateRect(hPlugInWnd, NULL, TRUE) ;

Display Management

This section discusses items that you should take into account when you design the drawing of a Today screen plug-in or a Home screen plug-in.

Screen Resolution

Working with the correct resolution definitely matters, for example, the BitBltfunction can be 10 times slower or more if the plug-in does not use the device resolution. The BitBltfunction transfers a screen buffer into another screen buffer; it is often used to transfer an off-screen buffer into the screen buffer. If the resolutions of the two-screen buffers are different, the BitBltfunction has to calculate each pixel of the targeted buffer according to the resolutions. If the resolutions of the two-screen buffers are equal, the BitBltfunction only has to copy the bytes. If a plug-in creates an off-screen buffer by using the CreateDIBSectionfunction with a 32 bit per pixel resolution ,the BitBltfunction that transfers the off-screen buffer into the screen buffer is much slower than if this plug-in has used the device resolution to create the device-independent bitmap (DIB) section. You can use the GetDeviceCaps(hDC, BITSPIXEL)function to get the device resolution. For the very same reason, a plug-in should create the device context it uses to draw by using the CreateCompatibleDCfunction instead of the CreateDCfunction.

High Resolution

This section only applies to the Today screen plug-in.

A Windows Mobile 2003-based plug-in is still compatible with Windows Mobile 5.0. However, because a Windows Mobile 2003–based plug-in cannot be aware of a high-resolution display, drawing this plug-in is handled in a specific manner where pixels are doubled to fit in the high-resolution display.

If the plug-in only targets Windows Mobile 5.0 devices, it is better to avoid this pixel doubling technique and generate a high-resolution aware plug-in.

Screen Rotation

This section only applies to the Today screen plug-in.

Because a Todayscreen plug-in is a child window of the Today screen window, it does not receive the WM_SETTINGCHANGE message, which is sent when the screen rotates. It receives the following messages:

  1. WM_TODAYCUSTOM_CLEARCACHE

  2. WM_TODAYCUSTOM_QUERYREFRESHCACHE

If the plug-in height changes due to screen rotation, the new height must be indicated at this time. The Today screen plug-in receives this message before the plug-in window rotates; therefore, it is dangerous to use the window’s rectangle to determine the screen's orientation. It is safer to use the system metrics by using GetSystemMetricsfunction.

  1. WM_WINDOWPOSCHANGED or WM_SIZE

  2. WM_PAINT

The screen rotation is faster if the plug-in does not change its height.

Memory Consumption

Memory is consumed in the context of the hosting process—Shell32.exe for Pocket PCs and Home.exe for Smartphones. The memory heap belongs to the process; therefore, allocation consumes memory from the process heap that other plug-ins or DLLs also use (for example, the Shell32 process on Pocket PCs also hosts the control panel applications). Allocating big chunks of memory (several megabytes) from the process heap without releasing them can create a memory shortage situation where memory allocation is no longer possible from the heap even though enough RAM may be available on a system-wide perspective. This can prevent a DLL from being loaded, for example, each time the system loads, a DLL it temporarily needs to allocate memory from the heap.

Some Windows API functions consume memory from the process heap (for example, the CreateDIBSectionfunction that allocates its buffer from the default process heap). For example, a plug-in that creates a DIB section that is 32 bit per pixels and is the same size as the screen will consume several megabytes from the process heap.

Initialization

This section discusses two topics: waiting for API readiness and enabling and disabling plug-ins in Settings.

Waiting for API Readiness

The Shell32 application is loaded early during the boot process; therefore, it can load a plug-in before an API set is ready for use. Using an API before it is ready causes the application to throw an exception. To determine if an API is ready, a plug-in can use the IsAPIReadyfunction—or even better, the API ready event. The name of this event is defined in the registry ( HKEY_LOCAL_MACHINE\System\Eventsin association with an event name, for example, ShellAPIReadyfor the ShellAPI).

Even though this applies more to Todayscreen plug-ins, it is safer to also apply it when designing Home screen plug-ins.

Enabling and Disabling Plug-ins in Settings

Each time the user changes the Todayscreen settings (for example, when enabling or disabling plug-ins or when changing the Todayscreen theme), the Shell32 process destroys the window for all of the previously enabled plug-ins and initializes all of the plug-ins that are enabled, which leads to the following series of events:

  • All of the previously enabled plug-ins receive a WM_DESTROY message.

  • The DLL of the disabled plug-in unloads, and the DLL main function is called (usually the DllMainfunction).

  • All of the enabled plug-ins are initialized, and the InitializeCustomItemfunction of each plug-in is called.

The InitializeCustomItemfunction could consequently be called several times without the DLL being unloaded because the plug-in remains enabled from one setting validation to another one. When the InitializeCustomItemfunction is called, memory allocation must be carefully handled. You should take care not to leak memory by allocating it twice or instantiating an object twice. A safe rule to follow is to allocate memory and instantiate objects when the InitializeCustomItemfunction runs and to free memory and delete objects when the WM_DESTROY message is received.

You should also consider that the window handle of the plug-in window will change because a new plug-in window is created each time the InitializeCustomItemfunction is called. This is very important to remember when the plug-in window is receiving notification messages.

Samples

This section introduces the three samples that this article illustrates.

Today Screen Skeleton

The Todayscreen sample (part of this article's download code sample ) writes text on the screen and handles screen rotation.

Home Screen Skeleton

The Homescreen sample (part of this article's download code sample ) is structured as follows:

  • The PluginFactoryclass implements the IClassFactoryinterface.

  • The SpPlugInBaseclass implements the standard interface that a Homescreen plug-in must implement. This class does not implement the content-related methods, such as the OnEventmethod, that are pure virtual. The SpPlugInBaseclass cannot be instantiated and must be derived by another SpPlugInclass, which implements those methods.

  • The SpPlugInclass derives from the SpPlugInBaseclass and implements all of the methods that are related with the plug-in's content. This class draws the plug-in by using the DrawTextfunction to keep things simple.

This three-class architecture simplifies the plug-in implementation by isolating the COM and class factory mechanisms in the PluginFactoryand the SpPlugInBaseclasses and focuses on the plug-in content by implementing the SpPlugInclass.

Notification

The Notification handling sample (part of this article's download code sample ) reuses the Today screen skeleton and adds the following:

  • The DataMgt_tclass that implements the worker thread/listener window structure. The worker thread creates the listener window and hosts its message loop. The listener window receives the POOM notification.

  • The PoomAgenda_tclass that deals with the POOM interface.

Conclusion

The main differences between a Today screen plug-in and a Home screen plug-in are the following:

  • Class factory and COM architecture is used in the Home screen plug-in—and not in the Today screen plug-in, which is a standard Win32® DLL.

  • The way Home screen and Today screen plug-ins are initialized.

  • The drawing structures are different: window versus rectangle—or, more accurately, window procedures versus the IHomePlugin::OnEventinterface.

  • A Today screen plug-in receives all WM_ messages that a child window can receive in addition to the messages that are directly sent to its window (for example, notification from POOM).

  • A Home screen plug-in is notified of PE_* events, such as PE_PAINT or PE_KEYDOWN. Consequently, a Home screen plug-in is not able to directly manage any notifications that are sent by the means of WM_ messages (for example, POOM notifications).

Both a Today screen and a Home screen plug-in runs in the context of the host process (Home.exe of Shell32.ex) with the windows message handler and interface methods of each plug-in managed by the same thread, which also manages the other plug-ins. Therefore, a plug-in should take care about how it interacts with its hosting process, thread, and with the other plug-ins—particularly from data management, drawing, and memory consumption perspectives. A plug-in should be designed to always consider that battery energy is a restricted resource on Windows Mobile–based devices and should always try to save it.

The following are online resources about the Todayscreen (Pocket PC):

The following is an online resource about the Homescreen (Smartphone):