讓你的上位機程序獨佔鰲頭

前言

有學員提出要求,上位機程序啓動之後,可以禁用Win組合,防止操作人員無操作或者退出程序。

實現思路

首先我們要了解一下鍵盤在PC上的工作原理,Windows系統所有的操作都是基於消息機制的,也就是說我們鍵盤上的每個按鍵其實都是往Windows底層發送一個消息,所以如果想要屏蔽掉某個按鍵或者功能,最直接的辦法就是消息攔截。

再說一下實現思路,就是使用鉤子Hook,這個我們之前講掃碼槍的時候也講過一點。

鉤子原理

鉤子是操作系統消息處理的一種機制。通過鉤子,應用程序可以安裝一個鉤子回調過程讓系統調用,從而監視系統中的消息隊列。在這些消息到達目標窗口之前對這些消息進行處理。

鉤子特點

  • 鉤子函數會降低操作系統的性能,因爲它增加系統處理每一個消息的開銷。

  • 操作系統支持多種類型的鉤子,每種類型都提供了它特有的消息處理機制。

  • 對於每種類型的鉤子,系統都維護一個各自獨立的鉤子鏈,鉤子鏈是一個指向用戶提供的回調函數鉤子過程的鏈表指針。

  • 鉤子儘量避免大量使用,對於一個鉤子,一般是需要的時候安裝,使用完成後,儘快卸載。

代碼實現

下面就直接貼代碼了,主要是在鍵盤鉤子處理那裏加了一些需要截獲的消息。

   public class Hook : IDisposable
    {
        public delegate int HookProc(int nCode, int wParam, IntPtr lParam);
        static int hHook = 0;
        public const int WH_KEYBOARD_LL = 13;
        HookProc KeyBoardHookProcedure;
        [StructLayout(LayoutKind.Sequential)]
        public class KeyBoardHookStruct
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        [DllImport("user32.dll")]
        public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
        [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
        public static extern bool UnhookWindowsHookEx(int idHook);
        [DllImport("user32.dll")]
        public static extern int CallNextHookEx(int idHook, int nCode, int wParam, IntPtr lParam);
        [DllImport("kernel32.dll")]
        public static extern IntPtr GetModuleHandle(string name);
        public void Start()
        {
            // 安裝鍵盤鉤子 
            if (hHook == 0)
            {
                KeyBoardHookProcedure = new HookProc(KeyBoardHookProc);
                hHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyBoardHookProcedure, GetModuleHandle(Process.GetCurrentProcess().MainModule.ModuleName), 0);
                //如果設置鉤子失敗. 
                if (hHook == 0)
                    Close();
                else
                {
                    RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
                    if (key == null)//如果該項不存在的話,則創建該項
                        key = Registry.CurrentUser.CreateSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System");
                    key.SetValue("DisableTaskMgr", 1, RegistryValueKind.DWord);
                    key.Close();
                }
            }
        }
        public void Close()
        {
            bool retKeyboard = true;
            if (hHook != 0)
            {
                retKeyboard = UnhookWindowsHookEx(hHook);
                hHook = 0;
            }
            RegistryKey key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Policies\System", true);
            if (key != null)
            {
                key.DeleteValue("DisableTaskMgr", false);
                key.Close();
            }
        }
        public static int KeyBoardHookProc(int nCode, int wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KeyBoardHookStruct kbh = (KeyBoardHookStruct)Marshal.PtrToStructure(lParam, typeof(KeyBoardHookStruct));
                if (kbh.vkCode == 91) // 截獲左win(開始菜單鍵) 
                    return 1;
                if (kbh.vkCode == 92)// 截獲右win 
                    return 1;
                if (kbh.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control) //截獲Ctrl+Esc 
                    return 1;
                if (kbh.vkCode == (int)Keys.F4 && (int)Control.ModifierKeys == (int)Keys.Alt) //截獲alt+f4 
                    return 1;
                if (kbh.vkCode == (int)Keys.Tab && (int)Control.ModifierKeys == (int)Keys.Alt) //截獲alt+tab 
                    return 1;
                if (kbh.vkCode == (int)Keys.Escape && (int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Shift) //截獲Ctrl+Shift+Esc 
                    return 1;
                if (kbh.vkCode == (int)Keys.Space && (int)Control.ModifierKeys == (int)Keys.Alt) //截獲alt+空格 
                    return 1;
                if (kbh.vkCode == 241)                  //截獲F1 
                    return 1; if (kbh.vkCode == (int)Keys.Control && kbh.vkCode == (int)Keys.Alt && kbh.vkCode == (int)Keys.Delete)
                    return 1;
                if ((int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Alt + (int)Keys.Delete)      //截獲Ctrl+Alt+Delete 
                    return 1;
                if ((int)Control.ModifierKeys == (int)Keys.Control + (int)Keys.Shift)      //截獲Ctrl+Shift 
                    return 1;
            }
            return CallNextHookEx(hHook, nCode, wParam, lParam);
        }

        public void Dispose()
        {
            Close();
        }

    }

鉤子使用

使用方法也很簡單,在窗體初始化的時候,採用無邊框並最大化窗體,然後啓動鉤子。

 

 在窗體關閉事件裏關閉鉤子,鉤子使用一定要及時關閉。

 

 

這樣運行程序後,如果沒有提供關閉程序的入門,似乎就只能重啓系統了,大家測試時要注意保存電腦現有程序及文件。

另外新一期的訓練營很快就要開始了,先提前透漏一下內容

 

 

 

 

 

 

 

 

-END-

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章