Disabling ctrl-alt-delete, alt-tab, Start and other combinations

This is a free translation of an article from tamas.io about programmatically disabling and enabling Windows hot keys using C #. Most recently, I myself needed such functions in my program and I was surprised to find that there is nothing about this in RuNet, and indeed there is very little said about it on the network. So, if it is interesting or also necessary, as it was to me - welcome!

I wrote this article in 2007 and it is still surfing the web and is mentioned in various discussions, including StackOverflow and DotNetSpider , so I decided to publish it again. This was relevant even then and was not tested on Windows 7, due to the fact that at that time it simply did not physically exist.
Before you continue reading, please note that this article does not encourage you to create malicious applications at all. You can use the code below for educational purposes or for entertainment.

After a little research on disabling keys and their combinations, I found out that there are several ways to change the behavior of the previously mentioned key combos.

Do not worry, we will not consider them here, but I will show how to work with them.

We use the editing capabilities of the C # registry to set / change the group policy for the CTRL-ALT-DEL key sequence. Let's see what can be done without writing a single line of code. Open "Start -> Run" and type gpedit.msc. Go to: User Configuration> Administrative Templates> System> CTRL + ALT + DELETE Options after clicking CTRL-ALT-DEL (User Configuration> Administrative Templates> System> CTRL + ALT + DELETE Options). This is the place where, in the standard way, you can set the action that will be triggered by clicking this combo. Double click on “Remove Task Manager”. Changing this parameter changes the value in Software \ Microsoft \ Windows \ CurrentVersion \ Policies \ System and the value DisableTaskMgr gets the value 1.

Now the task has become clearer.

Important, do not skip this line:

using Microsoft.Win32;


The method I wrote is as follows:

public void KillCtrlAltDelete()
        {
            RegistryKey regkey;
            string keyValueInt = "1";
            string subKey = @"Software\Microsoft\Windows\CurrentVersion\Policies\System";
            try
            {
                regkey = Registry.CurrentUser.CreateSubKey(subKey);
                regkey.SetValue("DisableTaskMgr", keyValueInt);
                regkey.Close();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }


Thus, we took care of changing the value of the combination CTRL-ALT-DEL. Consider the remaining combinations. It might have seemed complicated to you, but it’s easy. How to disable ALT + F4? Only 5 lines of code:

private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            e.Cancel = true;
            base.OnClosing(e);
        }


Good. I had to read a lot about the rest and now it will be difficult to name exactly those articles that helped me understand, but out of all there were 15 that contained at least some useful information. I will give you a method called a hook. The code snippet uses LowLevelKeyboardProc, which:

The LowLevelKeyboardProc procedure is a software-defined or library-specific function call procedure used in conjunction with the SetWindowsHookEx function. The system calls this function whenever a keyboard input event is about to be placed in the input stream queue. Keyboard input can go through the driver or through keybdevent calls. If the call occurred through a keybdevent call, then it was "injected". However, the WHKEYBOARDLL hook is not injected into another process. Instead, the context switches to another process on which the hook is set and called in its original form. Then, the context switches back to the application that caused this event.


And again, do not forget:


using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Diagnostics;


Here is everything else that may still be useful to you:


[DllImport("user32", EntryPoint = "SetWindowsHookExA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int SetWindowsHookEx(int idHook, LowLevelKeyboardProcDelegate lpfn, int hMod, int dwThreadId);
        [DllImport("user32", EntryPoint = "UnhookWindowsHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int UnhookWindowsHookEx(int hHook);
        public delegate int LowLevelKeyboardProcDelegate(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        [DllImport("user32", EntryPoint = "CallNextHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int CallNextHookEx(int hHook, int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        public const int WH_KEYBOARD_LL = 13;
        /*code needed to disable start menu*/
        [DllImport("user32.dll")]
        private static extern int FindWindow(string className, string windowText);
        [DllImport("user32.dll")]
        private static extern int ShowWindow(int hwnd, int command);
        private const int SW_HIDE = 0;
        private const int SW_SHOW = 1;
public struct KBDLLHOOKSTRUCT
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        public static int intLLKey;
        public int LowLevelKeyboardProc(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam)
        {
            bool blnEat = false;
            switch (wParam)
            {
                case 256:
                case 257:
                case 260:
                case 261:
                    //Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key,
                    blnEat = ((lParam.vkCode == 9) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 0)) | ((lParam.vkCode == 91) && (lParam.flags == 1)) | ((lParam.vkCode == 92) && (lParam.flags == 1)) | ((lParam.vkCode == 73) && (lParam.flags == 0));
                    break;
            }
            if (blnEat == true)
            {
                return 1;
            }
            else
            {
                return CallNextHookEx(0, nCode, wParam, ref lParam);
            }
        }
public void KillStartMenu()
        {
            int hwnd = FindWindow("Shell_TrayWnd", "");
            ShowWindow(hwnd, SW_HIDE);
        }
private void Form1_Load(object sender, EventArgs e)
        {
            intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(), 0);
        }

Obviously, you can programmatically return all values ​​by re-enabling all combinations:

public static void ShowStartMenu()
        {
            int hwnd = FindWindow("Shell_TrayWnd", "");
            ShowWindow(hwnd, SW_SHOW);
        }
public static void EnableCTRLALTDEL()
        {
            try
            {
                string subKey = @"Software\Microsoft\Windows\CurrentVersion\Policies\System";
                RegistryKey rk = Registry.CurrentUser;
                RegistryKey sk1 = rk.OpenSubKey(subKey);
                if (sk1 != null)
                    rk.DeleteSubKeyTree(subKey);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }
        }
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            UnhookWindowsHookEx(intLLKey);
        }


I hope you enjoyed the article and found something useful in it. I tried to collect here all the information that I could find on this topic.

From myself I’ll add that in .NET4 code of the form:


intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(), 0);


Does not work. You need to write something like:


var inst = LoadLibrary("user32.dll").ToInt32();
intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, inst, 0);


Well, at the beginning of the AddHooks structure code, among other things, import:


LoadLibrary:
[DllImport("kernel32", SetLastError = true, CharSet = CharSet.Unicode)]
public static extern IntPtr LoadLibrary(string lpFileName);


I hope the translation turned out to be not entirely bad and will prove useful to someone.
UPD: Link to the finished work program.

Also popular now: