Winform 键盘钩子,锁屏小工具的实现(一)

61 篇文章 1 订阅
56 篇文章 0 订阅

闲来无聊,给自己做了个锁屏小工具,在这里写写步骤,感兴趣的看看。

    新建Windws工程后将Form1的FormBorderStyle设置为None,使这个窗口没有边框;TopMost为True,使这个窗口始终在所有窗口的最上方;设置WindowState为Maximized,使窗口一开始就是最大化状态;设置ShowInTaskbar为False,使窗口不在任务栏出现。

    然后给窗体设置一张自己喜欢的背景图片,再把BackGroundImageLayout设置为None,使背景图片不重复。

    然后在窗口左下角放置一个密码框和一个按钮,按钮单击事件里面暂定密码为“123”就可以退出锁屏。

    现在按下Ctrl + F5启动程序,初步效果就已经出来了。

    但是这个时候按下Alt + F4就可以关闭锁屏工具,没有安全性可言,所以我们要使用键盘钩子来阻止这一行为。键盘钩子的原理就是通过Windows API实现我们的程序可以获取到所有的键盘事件,只要键盘稍有“响动”,锁屏工具就会第一时间获取到这一信息,然后我们就可以把这一信息拦截,拦截之后不告诉操作系统有按键事件发生,操作系统就不会做出反应。

    但是由于我们需要用键盘输入密码来解锁,所以我们不能屏蔽所有的按键,我们也不需要屏蔽所有的按键,只需要把Ctrl、Alt、Win、Tab等功能键屏蔽掉就够了,没了这些功能键,就不能用键盘关闭锁屏工具了。

    到底屏蔽哪些键,在下面这个类中的方法KeyboardHookProc中可以自行添加修改。

    安装钩子:InstallHook()、卸载钩子:UnInstallHook()。

001using System;
002using System.Collections.Generic;
003using System.Text;
004using System.Runtime.InteropServices;
005using System.IO;
006using System.Reflection;
007using System.Windows.Forms;
008  
009namespace LockScreen
010{
011    public class Hook_Keyboard
012    {
013        #region 私有变量
014  
015        /// <summary>
016        /// 键盘钩子句柄
017        /// </summary>
018        private IntPtr m_pKeyboardHook = IntPtr.Zero;
019  
020        /// <summary>
021        /// 钩子委托声明
022        /// </summary>
023        /// <param name="nCode"></param>
024        /// <param name="wParam"></param>
025        /// <param name="lParam"></param>
026        /// <returns></returns>
027        public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
028  
029        /// <summary>
030        /// 键盘钩子委托实例
031        /// </summary>
032        /// <remarks>
033        /// 不要试图省略此变量,否则将会导致
034        /// 激活 CallbackOnCollectedDelegate 托管调试助手 (MDA)。 
035        /// 详细请参见MSDN中关于 CallbackOnCollectedDelegate 的描述
036        /// </remarks>
037        private HookProc m_KeyboardHookProcedure;
038  
039        // 底层键盘钩子
040        public const int idHook = 13;
041  
042        /// <summary>
043        /// 安装钩子
044        /// </summary>
045        /// <param name="idHook"></param>
046        /// <param name="lpfn"></param>
047        /// <param name="hInstance"></param>
048        /// <param name="threadId"></param>
049        /// <returns></returns>
050        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
051        public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn,
052            IntPtr pInstance, int threadId);
053  
054        /// <summary>
055        /// 卸载钩子
056        /// </summary>
057        /// <param name="idHook"></param>
058        /// <returns></returns>
059        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
060        public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
061  
062        /// <summary>
063        /// 传递钩子
064        /// </summary>
065        /// <param name="pHookHandle">是您自己的钩子函数的句柄。用该句柄可以遍历钩子链</param>
066        /// <param name="nCode">把传入的参数简单传给CallNextHookEx即可</param>
067        /// <param name="wParam">把传入的参数简单传给CallNextHookEx即可</param>
068        /// <param name="lParam"></param>
069        /// <returns></returns>
070        [DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
071        public static extern int CallNextHookEx(IntPtr pHookHandle, int nCode,
072            Int32 wParam, IntPtr lParam);
073  
074        #endregion 私有变量
075  
076        #region 私有方法
077  
078  
079        /// <summary>
080        /// 键盘钩子处理函数
081        /// </summary>
082        /// <param name="nCode"></param>
083        /// <param name="wParam"></param>
084        /// <param name="lParam"></param>
085        /// <returns></returns>
086        /// <remarks>此版本的键盘事件处理不是很好,还有待修正.</remarks>
087        private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
088        {
089            //return 1;
090            KeyMSG m = (KeyMSG)Marshal.PtrToStructure(lParam, typeof(KeyMSG));
091            if (m_pKeyboardHook != IntPtr.Zero)
092            {
093                switch (((Keys)m.vkCode))
094                {
095                    case Keys.LWin:
096                    case Keys.RWin:
097                    case Keys.Delete:
098                    case Keys.Alt:
099                    case Keys.Escape:
100                    case Keys.F4:
101                    case Keys.Control:
102                    case Keys.Tab:
103                        return 1;
104                }
105            }
106            return 0;
107        }
108  
109        #endregion 私有方法
110  
111        #region 公共方法
112  
113        /// <summary>
114        /// 安装钩子
115        /// </summary>
116        /// <returns></returns>
117        public bool InstallHook()
118        {
119            //IntPtr pInstance = Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().ManifestModule);
120            IntPtr pInstance = (IntPtr)4194304;
121            if (this.m_pKeyboardHook == IntPtr.Zero)
122            {
123                this.m_KeyboardHookProcedure = new HookProc(KeyboardHookProc);
124                this.m_pKeyboardHook = SetWindowsHookEx(idHook, m_KeyboardHookProcedure, pInstance, 0);
125                if (this.m_pKeyboardHook == IntPtr.Zero)
126                {
127                    this.UnInstallHook();
128                    return false;
129                }
130            }
131  
132            return true;
133        }
134  
135        /// <summary>
136        /// 卸载钩子
137        /// </summary>
138        /// <returns></returns>
139        public bool UnInstallHook()
140        {
141            bool result = true;
142            if (this.m_pKeyboardHook != IntPtr.Zero)
143            {
144                result = (UnhookWindowsHookEx(this.m_pKeyboardHook) && result);
145                this.m_pKeyboardHook = IntPtr.Zero;
146            }
147            return result;
148        }
149  
150        [StructLayout(LayoutKind.Sequential)]
151        public struct KeyMSG
152        {
153            public int vkCode;
154            public int scanCode;
155            public int flags;
156            public int time;
157            public int dwExtraInfo;
158        }
159        #endregion 公共方法
160    }
161}
1修改我们刚刚的锁屏工具,在窗体加载的时候安装钩子,在窗体关闭ing的时候卸载钩子即可。
1启动程序观察效果,果然强大了。
1但是还是有问题,理论上是屏蔽了这些功能键了,但是按下Ctrl + Alt + Del的时候居然还
1是可以调出系统的任务管理器,并且任务管理器的窗口Top级别是最高的,所以可以通过任务管理器
1关闭锁屏工具,这个问题可以这样解决:
01/// <summary>
02/// 用Timer杀死任务管理器
03/// </summary>
04/// <param name="sender"></param>
05/// <param name="e"></param>
06private void timer1_Tick(object sender, EventArgs e)
07{
08    try
09    {
10        this.Activate();
11 
12        Process[] myProcess = Process.GetProcesses();
13        foreach (Process p in myProcess)
14        {
15            if (p.ProcessName == "taskmgr")
16            {
17                p.Kill();
18                return;
19            }
20        }
21    }
22    catch (Exception)
23    {
24 
25    }
26}

 

    这是我在Form中添加一个Timer的Tick事件,用这个事件来“杀死”任务管理器进程就OK了。

    到这里,我们的锁屏工具基本上已经刀枪不入了。锁屏之后除非有密码,别人是动不了被锁的电脑的。

    警告:卸载钩子这一步骤在程序被关闭时一定要执行,不然很麻烦,很可能出现锁屏工具已经关闭了,但是键盘还是被锁着在。然后建议在制作调试的过程中不启用Timer,以免一不小心出点小毛病输不了密码,键盘也被锁,任务管理器也打不开,那就只好重启电脑了。如果后期加了开机自启动功能,出现这毛病,重启都不顶事,哭去吧。

    虽然这个锁屏工具实现是锁屏的功能,安全性也还不错,但是这个简易的锁屏工具离真正的“产品”的要求还很远,比如密码不能修改、锁屏功能不能被快捷键呼出、锁屏工具不能开机自启动等细节问题。我将在接下来的几章里继续完善。

夫英雄者,胸怀大志,腹有良谋,有包藏宇宙之机,吞吐天地之志者也。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值