9

What would be the best way to make a Windows .NET application be the only program that can be used on a computer? I have come across timers or events to switch windows back to a window with matching text and some api32 calls to make a form top most.

Is it possible to make an application like the windows lock screen where nothing can be done except that what is on screen? I want to block users from doing other things and only let administrators get to the desktop.

Joel Coehoorn
  • 399,467
  • 113
  • 570
  • 794
Piotr Kula
  • 9,597
  • 8
  • 59
  • 85
  • 2
    I, as a user, would find such computer pretty useless :-) A computer capable of running a single application. I would get bored :-) – Darin Dimitrov Oct 18 '11 at 18:48
  • 3
    @DarinDimitrov: I think this is probably for some type of cash register software or something along those lines. Like a kiosk. – James Johnson Oct 18 '11 at 18:50
  • 1
    You mean something along the lines of a [kiosk mode](http://stackoverflow.com/questions/4617303/does-windows-7-have-a-kiosk-mode)? – Roman Oct 18 '11 at 18:52
  • Using [MadShy CodeHook](http://madshi.net/) you could try to catch `CreateProcess` calls and drop them if they don't lead to your application... it's not a complete solution, but a starting point... – Marco Oct 18 '11 at 18:52
  • I assume this is for some sort of examination software or similar? – Reddog Oct 18 '11 at 18:53
  • Ya- its solely for the use of a dedicated program- the user is provided with another computer to avoid him from trying to "hack" this one and he dl as many virii as he want on the other @Darin Dimitrov :) - So it is kiosk mode they call it now days :) Cool! – Piotr Kula Oct 18 '11 at 18:57
  • @R0MANARMY your answer is correct man- the link there to the PDF is excellent tutorial how to do what i need. that embedded restrictions one. – Piotr Kula Oct 18 '11 at 19:16
  • @ppumkin: Glad I could help. In the future try to give a little more context to the question so it comes off as *This will run on a cash register and nothing else should really be running beside it.* instead of *my program will be the awesomest ever, why would you want to run anything else?* – Roman Oct 18 '11 at 19:29
  • @R0MANARMY I understand but the nature of the program is delicate, and its not the awesomenest ever.. it just needs to be the only program running and nothing else. Nothing special about it and the shell execute does just that :) Thanks – Piotr Kula Oct 18 '11 at 19:39

3 Answers3

11

You need to run your application in kiosk mode.

External methods

[DllImport("user32.dll")]
private static extern int FindWindow(string cls, string wndwText);

[DllImport("user32.dll")]
private static extern int ShowWindow(int hwnd, int cmd);

[DllImport("user32.dll")]
private static extern long SHAppBarMessage(long dword, int cmd);

[DllImport("user32.dll")]
private static extern int RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);

[DllImport("user32.dll")]
private static extern int UnregisterHotKey(IntPtr hwnd, int id);

Constants

//constants for modifier keys
private const int USE_ALT = 1;
private const int USE_CTRL = 2;
private const int USE_SHIFT = 4;
private const int USE_WIN = 8;

//hot key ID tracker
short mHotKeyId = 0;

Methods

private void RegisterGlobalHotKey(Keys hotkey, int modifiers)
{
    try
    {
        // increment the hot key value - we are just identifying
        // them with a sequential number since we have multiples
        mHotKeyId++;

        if (mHotKeyId > 0)
        {
            // register the hot key combination
            if (RegisterHotKey(this.Handle, mHotKeyId, modifiers, Convert.ToInt16(hotkey)) == 0)
            {
                // tell the user which combination failed to register -
                // this is useful to you, not an end user; the end user
                // should never see this application run
                MessageBox.Show("Error: " + mHotKeyId.ToString() + " - " +
                    Marshal.GetLastWin32Error().ToString(),
                    "Hot Key Registration");
            }
        }
    }
    catch
    {
        // clean up if hotkey registration failed -
        // nothing works if it fails
        UnregisterGlobalHotKey();
    }
}


private void UnregisterGlobalHotKey()
{
    // loop through each hotkey id and
    // disable it
    for (int i = 0; i < mHotKeyId; i++)
    {
        UnregisterHotKey(this.Handle, i);
    }
}

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    // if the message matches,
    // disregard it
    const int WM_HOTKEY = 0x312;
    if (m.Msg == WM_HOTKEY)
    {
        // Ignore the request or each
        // disabled hotkey combination
    }
}

Disable hot keys

RegisterGlobalHotKey(Keys.F4, USE_ALT);

// Disable CTRL+W - exit
RegisterGlobalHotKey(Keys.W, USE_CTRL);

// Disable CTRL+N - new window
RegisterGlobalHotKey(Keys.N, USE_CTRL);

// Disable CTRL+S - save
RegisterGlobalHotKey(Keys.S, USE_CTRL);

// Disable CTRL+A - select all
RegisterGlobalHotKey(Keys.A, USE_CTRL);

// Disable CTRL+C - copy
RegisterGlobalHotKey(Keys.C, USE_CTRL);

// Disable CTRL+X - cut
RegisterGlobalHotKey(Keys.X, USE_CTRL);

// Disable CTRL+V - paste
RegisterGlobalHotKey(Keys.V, USE_CTRL);

// Disable CTRL+B - organize favorites
RegisterGlobalHotKey(Keys.B, USE_CTRL);

// Disable CTRL+F - find
RegisterGlobalHotKey(Keys.F, USE_CTRL);

// Disable CTRL+H - view history
RegisterGlobalHotKey(Keys.H, USE_CTRL);

// Disable ALT+Tab - tab through open applications
RegisterGlobalHotKey(Keys.Tab, USE_ALT);

Hide the taskbar

// hide the task bar - not a big deal, they can
// still CTRL+ESC to get the start menu; for that
// matter, CTRL+ALT+DEL also works; if you need to
// disable that you will have to violate SAS and 
// monkey with the security policies on the machine

ShowWindow(FindWindow("Shell_TrayWnd", null), 0);

Example form in kiosk mode

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

public partial class frmKioskStarter : Form
{                
    #region Dynamic Link Library Imports

    [DllImport("user32.dll")]
    private static extern int FindWindow(string cls, string wndwText);

    [DllImport("user32.dll")]
    private static extern int ShowWindow(int hwnd, int cmd);

    [DllImport("user32.dll")]
    private static extern long SHAppBarMessage(long dword, int cmd);

    [DllImport("user32.dll")]
    private static extern int RegisterHotKey(IntPtr hwnd, int id, int fsModifiers, int vk);

    [DllImport("user32.dll")]
    private static extern int UnregisterHotKey(IntPtr hwnd, int id);

    #endregion

    #region Modifier Constants and Variables

    // Constants for modifier keys
    private const int USE_ALT = 1;
    private const int USE_CTRL = 2;
    private const int USE_SHIFT = 4;
    private const int USE_WIN = 8;

    // Hot key ID tracker
    short mHotKeyId = 0;

    #endregion

    public frmKioskStarter()
    {
        InitializeComponent();

        // Browser window key combinations
        // -- Some things that you may want to disable --
        //CTRL+A           Select All
        //CTRL+B           Organize Favorites
        //CTRL+C           Copy
        //CTRL+F           Find
        //CTRL+H           View History
        //CTRL+L           Open Locate
        //CTRL+N           New window (not in Kiosk mode)
        //CTRL+O           Open Locate
        //CTRL+P           Print
        //CTRL+R           Refresh
        //CTRL+S           Save
        //CTRL+V           Paste
        //CTRL+W           Close
        //CTRL+X           Cut
        //ALT+F4           Close

        // Use CTRL+ALT+DEL to open the task manager,
        // kill IE and then close the application window
        // to exit

        // Disable ALT+F4 - exit
        RegisterGlobalHotKey(Keys.F4, USE_ALT);

        // Disable CTRL+W - exit
        RegisterGlobalHotKey(Keys.W, USE_CTRL);

        // Disable CTRL+N - new window
        RegisterGlobalHotKey(Keys.N, USE_CTRL);

        // Disable CTRL+S - save
        RegisterGlobalHotKey(Keys.S, USE_CTRL);

        // Disable CTRL+A - select all
        RegisterGlobalHotKey(Keys.A, USE_CTRL);

        // Disable CTRL+C - copy
        RegisterGlobalHotKey(Keys.C, USE_CTRL);

        // Disable CTRL+X - cut
        RegisterGlobalHotKey(Keys.X, USE_CTRL);

        // Disable CTRL+V - paste
        RegisterGlobalHotKey(Keys.V, USE_CTRL);

        // Disable CTRL+B - organize favorites
        RegisterGlobalHotKey(Keys.B, USE_CTRL);

        // Disable CTRL+F - find
        RegisterGlobalHotKey(Keys.F, USE_CTRL);

        // Disable CTRL+H - view history
        RegisterGlobalHotKey(Keys.H, USE_CTRL);

        // Disable ALT+Tab - tab through open applications
        RegisterGlobalHotKey(Keys.Tab, USE_ALT);

        // hide the task bar - not a big deal, they can
        // still CTRL+ESC to get the start menu; for that
        // matter, CTRL+ALT+DEL also works; if you need to
        // disable that you will have to violate SAS and 
        // monkey with the security policies on the machine
        ShowWindow(FindWindow("Shell_TrayWnd", null), 0);
    }

    /// <summary>
    /// Launch the browser window in kiosk mode
    /// using the URL keyed into the text box
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void button1_Click(object sender, EventArgs e)
    {
        System.Diagnostics.Process.Start("iexplore", "-k " + txtUrl.Text);
    }


    private void RegisterGlobalHotKey(Keys hotkey, int modifiers)
    {
        try
        {
            // increment the hot key value - we are just identifying
            // them with a sequential number since we have multiples
            mHotKeyId++;

            if(mHotKeyId > 0)
            {
                // register the hot key combination
                if (RegisterHotKey(this.Handle, mHotKeyId, modifiers, Convert.ToInt16(hotkey)) == 0)
                {
                    // tell the user which combination failed to register -
                    // this is useful to you, not an end user; the end user
                    // should never see this application run
                    MessageBox.Show("Error: " + mHotKeyId.ToString() + " - " +
                        Marshal.GetLastWin32Error().ToString(),
                        "Hot Key Registration");
                }
            }
        }
        catch 
        {
            // clean up if hotkey registration failed -
            // nothing works if it fails
            UnregisterGlobalHotKey();
        }
    }


    private void UnregisterGlobalHotKey()
    {
        // loop through each hotkey id and
        // disable it
        for (int i = 0; i < mHotKeyId; i++)
        {
            UnregisterHotKey(this.Handle, i);
        }
    }

    protected override void WndProc(ref Message m)
    {
        base.WndProc(ref m);

        // if the message matches,
        // disregard it
        const int WM_HOTKEY = 0x312;
        if (m.Msg == WM_HOTKEY)
        {
            // Ignore the request or each
            // disabled hotkey combination
        }
    }

    private void Form1_FormClosed(object sender, FormClosedEventArgs e)
    {
        // unregister the hot keys
        UnregisterGlobalHotKey();

        // show the taskbar - does not matter really
        ShowWindow(FindWindow("Shell_TrayWnd", null), 1);

    }
}

Here's an article you can check out:
http://www.c-sharpcorner.com/UploadFile/scottlysle/KioskCS01292008011606AM/KioskCS.aspx

Here's some packaged software to look into:
http://www.kioware.com/productoverview.aspx?source=google&gclid=CPeQyrzz8qsCFZFV7Aod6noeMw

James Johnson
  • 45,496
  • 8
  • 73
  • 110
  • Yea nice- i suppose this i s the best answer but i am actually going to use the link provided in the comments to a pdf how to change the defautl shell program-doing all that code wont be necessary and if the user wants the desktop i run the explorer shell from my"shell" application and all is good. Thanks for great answers! – Piotr Kula Oct 18 '11 at 19:15
4

If your intent is to block this permanently for a specified user, you can manage this through appropriate group policies.

For example in Local Group Policy Editor (Start menugpedit.msc), go to Local Computer PolicyUser ConfigurationAdministrative TemplatesSystem. You'll find two options:

  • Don't run specified Windows applications
  • Run only specified Windows applications

Of course, you have to do fine management of group policy to restrict other things for a specified user, preventing to change the configuration, to reboot the machine, etc. and you also have to make your application blocking special keys through keyboard hooks.

Remember: don't rely only on hooks, full screen mode and other things preventing the user from getting outside your application. If you do it, one day your application will crash, giving to the user the unlimited access to the underlying operating system, file system, etc.

Arseni Mourzenko
  • 50,338
  • 35
  • 112
  • 199
1

I found a much simpler way to do this not using kiosk mode or gpedits or any things like that.

In my application I made a button with these two damn simple things- no questions asked!

I used shell.cmd to start a click once application ,appref-ms and it works a charm.

'The logged in user has to be administrator or the app run as administrator once.

My.Computer.Registry.SetValue("HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\IniFileMapping\system.ini\boot", "Shell", "USR:Software\Microsoft\Windows NT\CurrentVersion\Winlogon")

'This will change the shell to your program for THIS LOGGED IN user- after re logon bye bye exploerer shell hello custom app!            

My.Computer.Registry.SetValue("HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon", "Shell", appPath & "\shell.cmd")`

Watch my software boot as if it owns windows!

Want to understand more how it works in the full apscect?

Piotr Kula
  • 9,597
  • 8
  • 59
  • 85