Customizing the Windows CE .NET User Interface, Part 2


Mike Hall
Microsoft Corporation

Steve Maillet
Entelechy Consulting

May 1, 2002

Download Ieshell.exe.

Last month we took a look at customizing certain user interface features of the Microsoft® Windows® CE .NET operating system. This month we extend this to cover building a custom shell using the Microsoft® Windows CE Internet Explorer. Of course, the same process could be used to create a custom shell using a stand-alone application.

Custom Shells

The Explorer shell provided with Platform Builder is a good general-purpose shell that allows users a great deal of flexibility, while maintaining a generally familiar look and feel. Many embedded devices require a more tightly controlled user experience; for example, HMI industrial controllers, self-service Kiosks, or possibly even the control system of the train I'm riding in as I write this. These types of systems require a custom shell that limits the device to a particular function or set of functions it was designed for. Fortunately, Windows CE was designed with this in mind, and allows you to use any application you want as the shell.

Let's look at some of the functionality a custom shell might need:

  1. Start up at boot time.
  2. Present user with an interface.
    • Receive user input (and act on it).
    • Display response to user.
    • Display current status of some operation(s).
  3. Change modes/Tasks.

Starting the Shell at Boot Time

Starting the shell at boot time is pretty easy—it's just a registry entry. The following extract from the registry shows how the standard shell (explorer.exe is loaded):

   "Depend50"=hex:14,00, 1e,00

After the kernel initializes, it scans the Init key looking for value entries of the form "LaunchXX" and loads the application listed in numerical order. The DependXX values specify the XX value of an application loaded by the kernel as binary values in the registry. (The "hex:" syntax is used in REG files for values of type REG_BINARY.) The data for this registry value is a set of DWORD values corresponding to the Launch values of other applications the program depends on.

Note   The data is defined as a sequence of bytes, so you must take into account that the operating system expects the data in little-endian order.

So the example translates to:

Launch explorer.exe after whatever application is listed as "Launch20" and the application listed as "Launch30." (These happen to be Device.exe and Gwes.exe.)

There is a catch in this mechanism. The dependency is designed for operating system dependent services. The device manager and GWES must actually have initialized to a point where they can be used before the shell can start using them. Therefore, the operating system can't just launch the applications randomly. (Well, actually it could, but that would leave each application to create its own mechanism for indicating it was ready for use—creating general havoc for developers the world over.) Fortunately, the Windows CE architects considered this and created a standard mechanism for indicating that an application is ready for use. Windows CE uses this mechanism to determine when it should launch the dependent applications. Any application loaded by the Init key should call SignalStarted(), with the command line of the application converted to a long integer as in the following example:


This call informs the operating system that the application has initialized itself to a point where it can now be relied upon for use by other applications.

Using the Browser as a Shell

Once you have gotten your application to load at boot time in place of the shell, it's time to get busy with the UI coding. Typically, a UI in embedded devices doesn't resemble the traditional Windows application, with its main window and menu, toolbars, status bar, and so on. Instead, an embedded device UI is usually quite visual, and often best created by professional graphics designers. (Most engineers don't even come close to that!) So it's often desirable for the programmer and graphics designer to work together. Such a meeting of minds is proving very successful in Web development and design. Fairly rich, visually pleasing interfaces are generated almost daily on the great WWW. Why not use that model in your embedded system UI design? Windows CE .NET includes a browser component that let's you do just that.

The browser component in Windows CE .NET is a subset of the Microsoft® Internet Explorer 5.5 browser control on the desktop. This component is a Microsoft ActiveX® control that provides all the browsing and rendering functionality in one reusable package. There is also a sample hosting application called IESAMPLE. (We'll be using that later on.)

The IESAMPLE application, which hosts the Internet Explorer browser control, provides a familiar Internet Explorer browser interface complete with menus, toolbars, and status bar. However, as previously mentioned, this isn't desirable in most embedded systems. What we need to have is an application that can use the browser in a "Full Screen" mode. Well it just so happens that the good folks at Microsoft thought of that, too. (Although, they failed to mention it in the documentation!) The IESAMPLE application includes a number of #if tests to enable or disable the menus, status bar, and favorites. So you only need to make a few minor modifications to the build of IESAMPLE to get what you need for a browser-based shell.

Setting Up the Project

First, download the source for the project IESHELL.exe, using the link at the top of this article.

The IESAMPLE application is located in _WINCEROOT\public\Internet Explorer\oak\IESAMPLE. As we've discussed in previous articles, it's generally not a good idea to modify the Microsoft provided code off the COMMON directory or any of the standard configurations. So you can copy the IESAMPLE files to a folder under your platform's workspace folder (that is, _WINCEROOT\MyDevice\IESHELL). IESAMPLE is set up to build using a SOURCES file. You can create a new blank Platform Builder project and add the files in the IESHELL folder you copied everything into. The easiest way to do this is to right-click on the project in the file view and click Add files to project. (Add everything except the 'SOURCES' and 'MAKEFILE' and options.cpp. Be sure to use the *.* filtering when adding files to the project to get the various resource files as well.)

Because the project was originally created using a SOURCES file, there are some extra settings you will need to make to the project before it will build correctly.

First, you will need to add the path to the ATL headers on the C/C++ tab under the Preprocessor category. (Be sure to click All Configurations so that the settings apply to each of the project configurations.)

Figure 1. Add the ATL include folders

From the same tab in the ProjectSsettings dialog, click the Precompiled Headers category and click the IESHELL project in the left side tree view. This will change the settings for all files in the project. The precompiled header is PRECOMP.H, so all files should be set to use it.

Figure 2. Setting the precompiled header

Next, click the stdafx.cpp file in the tree view to alter its settings to generate the pre-compiled header information through precomp.h.

Figure 3. Setting the precompiled header for stdafx.cpp

Next, click the IESHELL project in the tree and then click the Link tab. You will need to add the following libraries to the input libraries (note that they are separated by a space):

ole32.lib oleaut32.lib commctrl.lib uuid.lib wininet.lib winsock.lib

Figure 4. Adding additional required libraries

Then, on the Link tab, click the Output category, and set the entry point to WinMain, the Stack size to 0x20000, and the commit size to 0x1000.

Figure 5. Setting the reserve and commit sizes

The SOURCES file uses the RCADDNULL option, which adds a '\0' to the end of all resource strings, so they can be used directly with LoadString(). Unfortunately, there aren't any settings options for that directly in the IDE, so you will need to adjust the resource compiler settings to use the /n parameter manually in the Project Options. Click the Resources tab, and click the IESHELL project in the tree, so that the settings are made project wide for all RC files. The Project Options field is only editable when you have a single configuration selected, so you will need to make this adjustment for each configuration.

Figure 6. Adjusting the resource complier settings

Add the following to the top of the PRECOMP.H file:

#define NOFIND

#include "defines.h"

defines.h is needed to make sure some definitions are available even if the other headers and features are disabled by the NOxxxx defines. The NOxxxx defines could be set in the project settings dialog as another option. You must also comment out or remove the #include<pkfuncs.h> (Line 44), as it is not actually needed.

You'll need to make some changes in MainWnd.cpp as well:

  1. Replace all occurrences of IESAMPLE with IESHELL.
  2. Replace the lines 190-193 with the following code to handle the SignalStarted() call:
    // allow launching with command line arg
    // for development purposes. When loaded
    // from the init key initSignal will be non zero
     int initSignal = _wtol(lpCmdLine);
       if(HandleNewWindow2(_T(""), NULL))
          goto Cleanup;
       if(HandleNewWindow2(lpCmdLine, NULL))
          goto Cleanup;
  3. At the top of CMainWnd::~CMainWnd(), place an #ifdef block around the command bar support.
    #ifndef NOCOMMANDBAR
  4. In CMainWnd::MainWndProc(), move the #endif // NOCOMMANDBAR down to enclose both the WM_COMMAND and the WM_NOTIFY message.
  5. At the bottom of CMainWnd::Close(), enclose the command bar code in an #ifdef NOCOMMANDBAR block as follows:
    #ifndef NOCOMMANDBAR
        _himlCmdBand = NULL;
    #endif  //NOCOMMANDBAR

Next, you will need to add some build actions to get things going. You can use any HTML and image files you need for your own UI. We've provided a simple sample of what a WebPhone device might look like. At this point it would be appropriate to remind you that it's rare to find a software engineer who is also a good graphics designer. (This sample is no exception!) The major advantage of using the browser as the shell of a dedicated device is the separation of presentation from functionality. The DHTML can contain ActiveX objects that implement the core functionality of the device and are manipulated by Microsoft JScript® code to connect the UI to the primary device functionality.

To set the actions for the sample, from the Feature View, you will need to right-click the IESHELL.PBP and select settings from the popup menu. Click All Configurations and Pre-Make Image for the Build Step. Click New to create a new action to copy C:\WINCE400\PUBLIC\MyPad\IESHELL\Files\IESHELL.reg to the $(_FLATRELEASEDIR).

In the Make Image step, add an environment variable IMGIESHELL and set it to 1.

The registry file will be copied to the release directory and processed by the makeimg tool. IESHELL.REG is set up to test for the Environment variable IMGIESHELL, conditionally include the settings to launch IESHELL.EXE as the shell, and to specify the default home page.

Figure 7. Copying the IESHELL registry file to the _FLATRELEASEDIR

Click the BIB Info tab. Add any file; you can then edit the entry in the dialog to $(_FLATRELEASEDIR)\IESHELL.EXE, but be sure it's in the Modules section and is not compressed. Then add each of the files listed below as uncompressed in the Files section. These are the images and home page (shell.htm) for the HTML-based shell:


Figure 8. Adding files to BIB Info

Making the start page and the elements it loads uncompressed helps the page to load faster.

Once you have all of the changes and settings taken care of, you can build the project and see the result. It should look like the following:

Figure 9. The end result: an Internet Explorer shell for Windows CE

It doesn't really do anything particularly useful, but it does show how to set up a UI based on the browser. You can further enhance the functionality to support a set of navigation buttons for the mini-browser window, and even include an address bar. If you are really ambitious, you can enhance it to utilize the support available in Windows CE .NET for Voice over IP and Real-Time Communications.


Get Embedded

Mike Hall is a Product Manager in the Microsoft Embedded and Appliance Platform Group (EAPG). Mike has been working with Windows CE since 1996—in developer support, Embedded System Engineering, and the Embedded product group. When not at the office, Mike can be found with his family, working on Skunk projects, or riding a Honda ST1100.

Steve Maillet is the Founder and Senior Consultant for Entelechy Consulting. Steve has provided training and has developed Windows CE solutions for clients since 1997, when CE was first introduced. Steve is a frequent contributor to the Microsoft Windows CE development newsgroups. When he's not at his computer burning up the keys, Steve can be found jumping out of airplanes at the nearest drop zone.