Create a Windows CE Image That Boots to Kiosk Mode (Windows CE 5.0)

 

Mike Hall
Microsoft Corporation

March 2006

Applies to:
   Microsoft Windows CE version 5.0

Summary: This article describes how to create a Windows CE 5.0 image that boots directly into a "kiosk" type application.

Contents

Introduction
Build the New Image
Create the Startup Folder
Make the Application Run in Application Form

Introduction

In this article, I'll discuss how to create a Windows CE 5.0 image that boots directly into a "kiosk" type application. Windows CE 5.0 ships with a number of operating system templates which include: Gateway (headless), Internet Appliance (Windows Shell), and Windows Thin Client (RDP Client Shell), but nothing that can be easily modified to allow for kiosk mode. A device in kiosk mode can boot directly into an application without access to a shell, control panel, or a way to launch other applications. A Point of Service device or an ATM are good examples of kiosk devices.

I'll explain how to create the image by modifying the existing Windows Thin Client (WBT/RDP) operating system template file, which on my development PC, is found at C:\WINCE500\PUBLIC\COMMON\OAK\CATALOG\NEWPLATFORMWIZARDS\Windows_Thin_Client.xml

The plan is to remove the RDP Shell from the XML file, add an application and launch registry keys, and then boot to a black shell (no shell application running.) Once I've configured our modified Thin Client platform wizard XML file and built an operating system, I will be able to determine the list of running processes on the target device by using the Windows CE Shell Prompt in Platform Builder. I can gi proc (get a list of running processes) and see that all the expected processes are up and running (but not actually see a user interface on the target since we have removed the Windows Based Terminal Shell). The next step will be to add a simple UI application, add the launch registry keys, and then we're all set.

What follows are the instructions and a sample XML.

Build the New Image

The existing Windows CE operating system templates ship with one of three shells, Windows Shell (looks like Windows 95 with a Start button, Taskbar, Icons on the desktop, and file explorer etc...), Thin Client Shell (boots directly into the WBT/RDP shell application), and Command Shell (boots into the command processor). The Windows Shell would be ideal for a hand-held device, perhaps a barcode scanner, GPS receiver, RPOS terminal or similar that ships with a number of applications that the end user could choose from at runtime. The Command Shell is useful when building debug platforms to make it easy to walk the file system and launch processes, but may not be appropriate for a real-world embedded system. Perhaps the WBT/RDP shell is the most useful for building a "real" embedded system.

Removing the WBT/RDP Shell from the original Windows_Thin_Client.xml file is extremely easy, with a default install of Windows CE 5.0 the xml file can be found here: C:\WINCE500\PUBLIC\COMMON\OAK\CATALOG\NEWPLATFORMWIZARDS. The existing XML file contains a bunch of GUIDs which define the required operating system features, how do you determine which GUID to remove? Thankfully there's a handy MSDN Article, which was written for Windows CE 4.x, but is also valid for Windows CE 5.0.

The GUID you're looking for is 8432B78A-19F1-43AF-A42E-728A01AB2D10.

To create your shell-less operating system template:

  1. Open the existing Windows_Thin_Client.xml file.
  2. Remove 8432B78A-19F1-43AF-A42E-728A01AB2D10 from the DefaultSettings section.
  3. Change the PlatformTitle from "Windows Thin Client" to "Kiosk Template" or something similar.
  4. Save the file under a new name, such as Kiosk_Template.xml, in the same folder as the existing thin client xml file.

You can now use the New Platform Wizard to build a new operating system image based on the Kiosk_Mode.xml template. If you build for the Emulator or other reference board, you will notice that the operating system image boots with a black screen (this is expected since you don't have a shell.) If we include the Command Shell component and support for Console Window you could start CMD from Platform Builder and see that the operating system is responsive.

Tip The Command Shell can be started in one of two ways, either use the Windows CE Shell in Platform Builder to "s cmd" (start the cmd process) or select Run Programs from the Target menu, and type the name of the process you want to start, which in this case is "cmd."

Now we want to be able to start our application (or applications) at boot time. Typically this is enabled through the HKLM\Init registry key, which is acceptable but not optimal. The issue with using the HKLM\Init key is that applications need to be written so that they are started by the Init registry key. Any application launched through this key needs to call SignalStarted( ); to let the operating system know that the application has started. This is important during the startup of the operating system because some processes rely on other processes having been started in order to work correctly. An example would be GWES (the Graphics Windowing and Event Sub-System) which relies on the device driver manager (device.exe) being started before GWES can start. I'd much rather take any application, drop it into a Startup folder and have the operating system launch the application at boot time without needing to worry about the boot sequence or my application needing to call the SignalStarted API. Interestingly, the Windows CE Standard Shell already does this. It's time to (borrowing a Star Wars quote here) "Use the Source, Luke." We can lift the source from the Windows CE Standard Shell and have this launch our applications from our own Startup folder.

Create the Startup Folder

There are a few things we need to think about before we create a Startup folder on the device and drop an application into the folder to be launched during boot of the Windows CE operating system image:

  1. How to create the \Startup folder as part of the operating system image.
  2. How to include our application(s) in the \Startup folder so they launch at boot time.
  3. How to create a Launch application that examines the \Startup folder and launches any applications found here.

Before we get into the specifics of making this work, we should determine why we're doing this. The Windows Shell exposes a mechanism to enumerate all files in the \Start Menu\Programs\Startup folder and launch the processes. This is an ideal solution because the applications being launched don't need to be modified to be started in this way. The other option for launching an application at boot time is to use the HKLM\Init keys, this requires that the application call back into the operating system by calling SignalStarted( ); to let the operating system know that the application is running. The reason for this is that the HKLM\Init keys have two parts, LaunchXX and DependXX. The LaunchXX key (where XX is a numeric value) simply points at the executable to launch. For example, take the following snippet from my operating system image registry file (once the operating system is built, the complete registry can be examined in text form in the build release folder as reginit.ini)

[HKEY_LOCAL_MACHINE\init]        "Launch10"="shell.exe"        "Launch20"="device.exe"        "Depend20"=hex:0a,00        "Launch30"="gwes.exe"        "Depend30"=hex:14,00

The snippet from the registry above launches three processes, Shell, Device, and GWES. Notice that device.exe (Launch20) has a dependency on Hex:0a (10 decimal). This equates to Launch10, or shell.exe, so the Shell process needs to signal the operating system that it's up and running so that any dependencies (in this case device.exe) can then be started. The same is also true of gwes.exe (launch30), device.exe depends on hex:14 (20 decimal), so GWES can't run until device.exe calls SignalStarted. You can have multiple dependencies; a Thin Client operating system image will have the WBT Shell depending on hex:14,00,1e,00 (Launch20 and Launch30), so both Device and GWES need to be up and running before the shell starts, make sense?

So, the plan is to create a new Platform Wizard based on the existing Thin Client template.

You can download the updated file here, and then drop the new template file in the Windows CE 5.0 Platform Wizard folder: \WINCE500\PUBLIC\COMMON\OAK\CATALOG\NEWPLATFORMWIZARDS.

When you restart Platform Builder you will have a new Kiosk template to work with that is an exact mirror of the Thin Client template file with the WBT/RDP shell removed. The next step is to replace the old RDP shell with some simple boot time code that examines the \Startup folder (which we will need to create) and launches any applications that we find. The code to do this already exists in the existing Windows CE Explorer Shell code: \wince500\public\shell\oak\hpc\explorer\main\explorer.cpp, take a look at the ProcessStartupFolder code.

Here's my simple boot time application, I've called this PlatformStartup.exe. The meat of the application is only about 10 lines of code. This uses the Win32 FindFirstFile, FindNextFile APIs to walk through the files in the \Startup folder and launch the applications.

// PlatformStartup.cpp : Defines the entry point for the application.//#include "stdafx.h"void ProcessStartupFolder();int WINAPI WinMain(HINSTANCE hInstance,                     HINSTANCE hPrevInstance,                     LPTSTR     lpCmdLine,                     int       nCmdShow){ // Since this is application is launched through the registry HKLM\Init we need to call SignalStarted passing in the command line parameter SignalStarted(_wtol(lpCmdLine)); ProcessStartupFolder( ); return 0;}// The purpose of this function is to start all applications found in our custom Startup folder// the Windows Explorer shell contains a "Special Folder" \Start Menu\Programs\Startup - CSIDL_STARTUP// For this demo I'm going to override this with a fixed location folder called "\Startup"// This code is taken from the Microsoft Windows CE Shared Source in the following location.// c:\wince500\public\shell\oak\hpc\explorer\main\explorer.cppvoid ProcessStartupFolder(){    WCHAR szPath[MAX_PATH];    HANDLE hFind = NULL;    WIN32_FIND_DATA fd = {0};    WCHAR pszFileName [MAX_PATH]; // Note that we will need to create the Startup folder // this can be achieved in one of two ways // // 1. Create the Startup Folder using this projects .DAT file // or.. // 2. Map our applications into the Startup Folder using CEFileWiz (my prefered option) lstrcpy(szPath,L"\\Startup\\*.*");    hFind = FindFirstFile(szPath, &fd);    if (INVALID_HANDLE_VALUE != hFind)    {        SHELLEXECUTEINFO sei = {0};        sei.cbSize = sizeof(sei);        sei.nShow = SW_SHOWNORMAL;        sei.lpFile = pszFileName;        do        {   lstrcpy(pszFileName,L"\\Startup\\");            if ((!(FILE_ATTRIBUTE_DIRECTORY & fd.dwFileAttributes)) &&                (0 != _tcsicmp(TEXT("desktop.ini"), fd.cFileName)))            {    lstrcat(pszFileName, fd.cFileName);                ShellExecuteEx(&sei);            }        } while (FindNextFile(hFind, &fd));        FindClose(hFind);    }}

The next step is to make the application start at boot time. With Windows CE 5.0 this is super easy. Each project contains its own personal .reg, .bib, and .dat files, so we can add the following to our projects .reg file to start the application after Device and GWES are up and running.

[HKEY_LOCAL_MACHINE\init]        "Launch50"="PlatformStartup.exe"        "Depend50"=hex:14,00,1E,00

The final step is to add our custom shell application. In this case I've written a very simple C# application that contains a Button and TextBox, click the button and "Cool Tools!" appears in the TextBox, but that's not the point, right? What I'm showing here is that I can build a kiosk type device and build my custom shell using Win32/C/C++/C#/VB without needing to know (at the application level) anything about the boot process of the Windows CE operating system.

I've used CEFileWiz to create a custom CEC file that gives me everything I need to directly add the C# application binary to the Windows CE operating system image (there's a tutorial here that shows how to do this). The interesting thing is how to map the ShellApp.exe from the \Windows folder (the default location for any application or file in the Windows CE operating system) to the \Startup folder. CEFileWiz creates a project file that doesn't compile or link anything, but instead makes sure the .bib, .dat, and .reg files are set up correctly to include the application or file into the operating system. For our ShellApp.exe we want to map the application from the \Windows folder to the \Startup folder, this is very easy, here's the ShellApp.dat file:

root:-Directory("\"):-Directory("Startup")Directory("\Startup"):-File("ShellApp.exe","\windows\ShellApp.exe")

And the end result? A Windows CE operating system image that can still be customized by adding the technologies you need, and at the same time makes it easy to create kiosk type devices, perhaps an airport check-in terminal or a ticket machine at a train station.

And here's the final custom shell application up and running.

Aa446914.windowsce_kioskmode1(en-us,MSDN.10).gif

Figure 1. Final Custom Shell Application

Make the Application Run in Application Form

So, the next question about the Windows CE Kiosk mode is: how to make a .NET Compact Framework application run without borders, caption, and control box, etc... so you only see the application form. This is remarkably easy, simply set the following properties on the form (I also set the form style to be maximized on startup):

set FormBorderStyle = NoneSet ControlBox = FalseSet MaximizeBox = FalseSet MinimizeBox = FalseSet Text = 

Summary

Following is a summary of the exercises provided in this article:

  • Removed the WBT/RDP Shell from the original Windows_Thin_Client.xml file
  • Created a shell-less operating system template
  • Built a new operating system image based on the Kiosk_Mode.xml template.
  • Created a new Platform Wizard based on the existing Thin Client template
  • Replaced the old RDP shell with simple boot time code that examines the \Startup folder
  • Made the application start at boot time
  • Added a custom shell application
  • Made the .NET Compact Framework application run in application form