前言
有學員提出要求,上位機程序啓動之後,可以禁用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-