Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / WinMobile

Windows Mobile: Implement Kiosk Mode

3.67/5 (6 votes)
10 Aug 2007CPOL4 min read 1   975  
Windows Mobile: Implement kiosk mode

Introduction

Windows Mobile is a great production device. But by default, the device gives access to all functionalities (e-mail, contacts ...) and in particular context, you will probably be interested to restrict end-user access to some of these functionalities.

You'll have two options:

  • Integrate in the standard Sheel
  • Customize the system in kiosk mode

I'll focus on the second option. In order to set the system in kiosk mode, we'll have to:

  • Write an application with a screen which will work like the 'Today' screen
  • Control the hardware button to restrict access to Windows Mobile functionalities
  • Of course, have the application launch at startup
  • This is a non exhaustive list...

Background

I will not focus on Compact Framework development and OS low level library interaction. But keep in mind the .NET Compact Framework Architecture:

  • Framework
  • Common Language Runtime
  • Windows CE

You will then understand why we reference microsoft.windowsce.forms for low level functionality.

I also use OpenNETCF www.openNETCF.com for reading/writing registry. The library is fully explained on their web-site.

Using the Code

Our first task is to create a new Smart Device project from Visual Studio. As mentioned in the introduction, we'll set properties of the default Form Form1.cs in order to create a 'Today' like screen. You can do it using the properties windows or by code :

C#
public frmKiosk()
{
    InitializeComponent();

    ControlBox = false;
    FormBorderStyle = FormBorderStyle.None;
    MaximizeBox = false;
    MinimizeBox = false;
    WindowState = FormWindowState.Maximized;
}

Now, we'll have to control hardware button. This is done using the Microsoft.WindowsCE.Form.MessageWindows. This class will allow us to intercept Windows Messages and decide how to handle them (internal routine, raising events to be handled by other class, or ... do nothing). This will allow us to intercept messages sent by hardware button and simply decide to not react to them!

The logic is quite simple:

  • Create a class which will inherit from MessageWindows. Override the WndProc method to catch windows message and implement our own business logic. We will intercept only HOTKEY message, but the same code could be used to handle all windows message types (full list can be found at http:\\www.pinvoke.net)
  • Unregister the hardware button: by default, message raised by hardware button is handled by the default process
  • Register the hardware button: message raised by hardware button will be handled by our custom MessageWindows.

The code of our custom MessageWindows will be like this:

C#
public class internalMessageWindow : MessageWindow
{
        // Which message type ?
        public const int WM_HOTKEY = 0x0312;

        Form referedForm;

        public internalMessageWindow(Form referedForm)
        {
            this.referedForm = referedForm;
        }

        protected override void WndProc(ref Message msg)
        {
            switch (msg.Msg)
            {
                case WM_HOTKEY:
                    // Do no reply to this key ...
                    return;
            }
            base.WndProc(ref msg);
        }
}

We have now to link our form with our custom WindowsMessage:

C#
FormCode
{    
    internalMessageWindow messageWindow;
    public Form Constructor()
    {
        this.messageWindow = new internalMessageWindow(this); 
    }        
}

And unregister/register hardware buttons using UnregisterFunc1 and RegisterRecordKey from coredll.dll (see http:\\www.pinvoke.net for signature detail.

C#
FormCode
{    
    public Form Constructor()
    {
        ...
        RegisterHKeys.RegisterRecordKey(this.messageWindow.Hwnd);
    }        
}
public class RegisterHKeys
    {
        [DllImport("coredll.dll", SetLastError = true)]
        public static extern bool RegisterHotKey
        ...
        and
        private static extern bool UnregisterFunc1
        ...
        
        public static void RegisterRecordKey(IntPtr hWnd)
        {
            UnregisterFunc1(KeyModifiers.Windows, (int)KeysHardware.Hardware1);
            RegisterHotKey(hWnd, (int)KeysHardware.Hardware1, 
		KeyModifiers.Windows, (int)KeysHardware.Hardware1);
            
            // Repeat for every single hardware button you wan to handle
        }
    }

Now, we need to force our application to start every time the Windows Mobile is started. This could be done using the CeRunAppAtEvent function of the coredll.dll library. This function allows linking an application to a specific event of the device. In our context, we'll link our application to the Wakeup event. This means that every time the device is started, the Wakeup event will be raised, and as we will link our application with this event, our application will be started.

To link application to event, we'll use this code:

C#
Win32.CeRunAppAtEvent(_kioskName, NotificationEvent.Wakeup);

And we'll use this code to 'unlink' application / event:

C#
Win32.CeRunAppAtEvent(_kioskName, NotificationEvent.None);

So now, we have a start page, which appears every time the device is started. And we have also caught button events to disable hardware interaction. The final step is to allow the end-user to launch a specific application and wait that this application be closed to return to our start page.

This is a quite an easy step, using ProcessStartInfo class. This will allow us to start an application in a new process and put our current application in a waiting state, waiting that a specific process exit.

To start a new process, we'll use this code, which will return the process handler:

C#
private static Process LaunchApp(string filename)
{
    ProcessStartInfo s = new ProcessStartInfo();
    s.FileName = filename;
    s.UseShellExecute = true;
    return Process.Start(s);
}

And we have just to add routine to start an application, waiting the process to exit, with this code:

C#
private void but_Click(object sender, EventArgs e)
{
    this.Hide();
    Process ela = LaunchApp(application2);
    ela.WaitForExit();
    this.Show();
}

Things to be Aware

  • Hard reset of the device is not handled. Doing an hard reset will unsubscribe the application from the Wakeup event.
  • This solution is not portable! Form is designed for a specific resolution (240x320 in this sample) and device with the default four hardware buttons. Installing in a device with other specification will fail.

How To

Handling Non Standard Hardware Button

The sample is based on default device, with four buttons. If your target device has more buttons, or that MessageWindow didn't catch button interaction, you'll have to validate your button code. Use Registry Editor (Remote Registry Editor) and go in HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Shell\Keys\. You will see multiple "Folders", corresponding to your hardware keys, like 40C1, 40C2, ... Convert the last two letters to Decimal and you will get your button key (C1=193,C2=194,...)

Conclusion

This sample is far from a production product, but show that handling specific device like PocketPC is quite easy. Interacting with such hardware needs a little bit of pinvoke, as compact framework encapsulates some but not all functionalities. Any comments/proposition are welcome.

Reference

History

  • 08/10/2007: Posted to CodeProject

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)