Deploy Surface SDK 2.0 app to PixelSense and Windows 7 kiosk mode

The goal of this article is to demonstrate how to use the same assembly, basically the same project, to target both PixelSense with it’s User Mode and any other Windows 7 operating system giving to the customer the ability to have a “kiosk mode”.

For “kiosk mode” I mean a mode where the user will not be able to access to underlying operating system.

Even if I advice not to guarantee this mode to the customer we used this approach in may scenarios without problems.

When the customer asks for an high level of security and you would like to offer a 100% bullet proof kiosk mode the solution is to use embedded os this will mean having some expertise that are not the goal of this article.

Well let’s start with our solution.

To target both PixelSense and Window 7 the solution is simple, this was already discussed in some other blog, but I would like to discuss it again for completeness:

  • Place all you view / window / user control or whatever in a main user control that will act as a container
  • Create a Surface Window and a WPF Window and in both insert your main container
  • Modify the App.xaml file by adding the necessary logic to determine if the app is running on a PixelSense device or not and based on this launch the Surface or the WPF window.
    Remove the uri property from the XAML an in the code behind add the override method onstartup:
        protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);

            Window window = null;

            if (InteractiveSurface.PrimarySurfaceDevice.IsTagRecognitionSupported == true)
                window = new SurfaceShell();
            else
                window = new WindowShell();


            if (window != null)
            {
                Application.Current.MainWindow = window;
                window.Show();
                window.Activate();
                window.Title = "Your Company Name - your app name";
            }
        }

 

Great! Now our application will work properly on both PixelSense, Windows 7 and on Windows 8. Also on PixelSense it will use the input stack of the Surface SDK 2.0 and on Windows 7 and 8 it will use the standard input stack, in that way the application will work correctly even in Windows 8 avoiding the issue of the Surface input stack not working on Windows 8.

Now let’s enable the kiosk mode on Windows 7. This mode will not work properly on Windows 8 but even without guarantee, as discussed above, it works great on Windows 7.

We need a setting that we will use to determine if we want that the app will start normally or in kiosk mode to achieve this result we can use an App.config file with an app setting:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <appSettings>
    <add key="KioskMode" value="true" />
  </appSettings>
</configuration>

 

On our application we can read the settings by adding a reference to the System.Configuration namespace and by adding a simple wrapper used as helper to access our settings:

    internal sealed class ConfigManager
    {
        public static bool KioskMode
        {
            get
            {
                try
                {
                    return Convert.ToBoolean(ConfigurationManager.AppSettings["KioskMode"]);
                }
                catch
                {
                    return false;
                }
            }
        }
    }

 

Now let’s open the WPF Window and let’s add the code needed for the hiok mode.

First of all, at the startup we need to check if we need the kiosk mode or not, if yes we need to kill the explorer.exe process, we need to disable some key combination and we need a window without border. To achieve that we need some interop:

        [DllImport("user32.dll")]
        public static extern int FindWindow(string lpClassName, string lpWindowName);

        [return: MarshalAs(UnmanagedType.Bool)]
        [DllImport("user32.dll", SetLastError = true)]
        public static extern bool PostMessage(int hWnd, uint Msg, int wParam, int lParam);

 

then we need to use it:

        public WindowShell()
        {
            this.WindowState = WindowState.Maximized;
            if (ConfigManager.KioskMode)
            {
                this.WindowStyle = WindowStyle.None;
                int hwnd;
                hwnd = FindWindow("Progman", null);
                PostMessage(hwnd, /*WM_QUIT*/ 0x12, 0, 0);
            }

            InitializeComponent();
        }

 

Fantastic! if needed we have a Kiosk mode but now hot to exit from it?

Simple we need to enable a secret key combination to close our app. notthing else that a routed command: 

        // Routed command to manage the keycombination to close the window
        public static RoutedCommand CloseCommand = new RoutedCommand();

 

used in the xaml:

    <Window.CommandBindings>
        <CommandBinding Command="{x:Static this:WindowShell.CloseCommand}" Executed="CloseCommandExecuted"/>
    </Window.CommandBindings>

 

on the ctor 

// Add the shortcut key(s) that should invoke method: 
CloseCommand.InputGestures.Add(new KeyGesture(Key.S, ModifierKeys.Control));

 

and then the CloseCommandExecuted

simply

this.Close();

 

Perfect! but what if we start the app to test the kiosk mode all works fine except that when we close the application we don’t have the task bar any more!

we need to launch the explorer.exe process closed at the start of the application to avoid the operating system to interact with the user:

        protected override void OnClosed(EventArgs e) 
        { 
            if (ConfigManager.KioskMode) 
            { 
                Process.Start(PROCESS_EXPLORER); 
            }

            base.OnClosed(e); 
        }

 

And that’s all now we have an application that works with PixelSense, works with Windows 7 and 8 and with Windows 7 has a built in kiosk mode

You can download a full working sample of the article discussed above on the MSDN Code Gallery

 

Ultimi Post

Discalmer

Articles and content of this blog aren't and shouldn't be interpreted as professional advice or opinions. Author writes on a personal basis and as part of their own research, experimentation and knowledge. Opinions expressed aren't in any way attributable to professional affiliations / institutional thereof or to opinions that the author express as part of their roles / positions that may be quite different from that reported here.