在进行winform软件开发时,需要实现锁屏功能。本文就主要介绍此功能实现方式。
实现思路
- 此功能分三个界面,分别是操作界面、锁屏界面、解锁界面
- 操作员在操作界面输入锁屏密码,并启动锁屏功能。锁屏界面显示
- 解锁时,操作员点击锁屏界面,解锁界面显示,操作员输入解锁密码,锁屏界面关闭,主画面显示
知识点
钩子机制
钩子是Windows操作系统提供的消息处理机制平台,应用程序可通过设置回调函数监视指定窗口消息,钩子可在消息到达目标窗口前捕获键盘、鼠标等输入事件,处理函数可修改消息内容或终止传递流程,可以理解为监视窗口和键盘、鼠标等动作,并根据此动作,执行其他功能,比如屏蔽键盘、记录键盘按下、窗体关闭等。实现代码如下:
csharp
private IntPtr pKeyboardHook = IntPtr.Zero;//键盘钩子句柄
//钩子委托声明
public delegate int HookProc(int nCode, Int32 wParam, IntPtr lParam);
private HookProc KeyboardHookProcedure;//键盘钩子委托实例,不能省略变量
public const int idHook = 13;//底层键盘钩子
//安装钩子
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr pInstance, int threadID);
//卸载钩子
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(IntPtr pHookHandle);
//键盘钩子处理函数
private int KeyboardHookProc(int nCode, Int32 wParam, IntPtr lParam)
{
KeyMSG m = (KeyMSG)Marshal.PtrToStructure(lParam, typeof(KeyMSG));//键盘消息处理
if (pKeyboardHook != IntPtr.Zero)//判断钩子句柄是否为空
{
switch (((Keys)m.vkCode))//判断按键
{
case Keys.LWin://键盘左侧的Win键
case Keys.RWin://键盘右侧的Win键
case Keys.Delete://Delete键
case Keys.Alt://Alt键
case Keys.Escape: //Esc键
case Keys.F4: //F4键
case Keys.Control://Ctrl键
case Keys.Tab://Tab键
return 1;//不执行任何操作
}
}
return 0;
}
//安装钩子方法
public bool InsertHook()
{
IntPtr pIn = (IntPtr)4194304;//将4194304转换为句柄
if (this.pKeyboardHook == IntPtr.Zero)//不存在钩子时
{
//创建钩子
this.KeyboardHookProcedure = new HookProc(KeyboardHookProc);
//使用SetWindowsHookEx函数安装钩子
this.pKeyboardHook = SetWindowsHookEx(idHook, KeyboardHookProcedure, pIn, 0);
if (this.pKeyboardHook == IntPtr.Zero)//如果安装钩子失败
{
this.UnInsertHook();//卸载钩子
return false;
}
}
return true;
}
//卸载钩子方法
public bool UnInsertHook()
{
bool result = true;
if (this.pKeyboardHook != IntPtr.Zero)//如果存在钩子
{
//使用UnhookWindowsHookEx函数卸载钩子
result = (UnhookWindowsHookEx(this.pKeyboardHook) && result);
this.pKeyboardHook = IntPtr.Zero;//清空指针
}
return result;
}
//键盘消息处理结构
[StructLayout(LayoutKind.Sequential)]
public struct KeyMSG
{
public int vkCode;//键盘按键
}
泛型集合
List 本功能用到泛型集合,在锁屏功能中作用是将所有的窗体保存到集合中,然后解锁后,全部关闭,避免出现窗体未全部关闭。并且此泛型集合作为全局静态变量。
csharp
public static List<Form> listforms = new List<Form>();//窗体集合,主要用来在锁屏及解锁时使用
Process
由于winform是基于windows系统开发的,在锁屏阶段,为避免通过热键等其他方式绕过锁屏功能,需要定时监督windows系统进程,确保在锁屏阶段,windows系统无法执行其他操作。
关于Process,本文只介绍进程的启动和关闭。详细功能可参考官方文档。
csharp
using System;
using System.Diagnostics;
class Program
{
static void Main()
{
//启动notepad
Process process = Process.Start("notepad.exe");
System.Threading.Thread.Sleep(2000); // 等待2秒
process.Kill();//关闭notepad
}
}
Cursor
代表用于绘制鼠标指针的图像。
本文主要介绍Cursor的属性Clip:
获取或设置表示光标的剪辑矩形的边界。
csharp
Cursor.Clip = new Rectangle(x, y, size.Width, size.Height);//设置鼠标指针的边界
作用主要是当开始解锁时,限制鼠标活动范围只在解锁界面。
size
存储一个有序整数对,用于指定 Height 和 Width。
csharp
Cursor.Clip = new Rectangle(x, y, size.Width, size.Height);//设置鼠标指针的边界
窗体数据传送
在进行winform开发时,会需要将数据通过窗体传递,其传递机制为:
假定有窗体A和窗体B,现在需要将窗体A的数据传递给窗体B
- 在窗体B定义公共变量,tagA和TagB
- 在窗体A引用窗体B的两个变量,并将数据发送给这两个变量
其实也可以加载事件。
关键代码
- 窗体A:锁屏操作界面

csharp
Frm_LScreen Frm_LScreen = new Frm_LScreen();
private void button1_Click(object sender, EventArgs e)
{
if(textBox2.Text.Trim()== ""||textBox3.Text.Trim() =="")
{
MessageBox.Show("请输入锁屏密码!", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
else
{
if(textBox2.Text.Trim()==textBox3.Text.Trim())
{
Frm_LScreen.size = this.Size;//
Frm_LScreen.x = this.Location.X;
Frm_LScreen.y = this.Location.Y;
Frm_LScreen.infos = textBox1.Text.Trim();
Frm_LScreen.pwd = textBox2.Text.Trim();
this.Hide();
Operator.listforms.Add(Frm_LScreen);
Frm_LScreen.ShowDialog();
}
else
{
MessageBox.Show("输入的两次密码不一致", "系统提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
return;
}
}
}
private void button2_Click(object sender, EventArgs e)
{
this.Close();
}
private void textBox3_KeyPress(object sender, KeyPressEventArgs e)
{
if(e.KeyChar==13)
{
button1.Focus();
}
}
- 窗体2:锁屏界面

csharp
#region 公共变量
public Size size;//记录窗体的大小
public int x;
public int y;
public string infos;
public string pwd;
MyHook myHook=new MyHook ();
#endregion
private void Frm_LScreen_Load(object sender, EventArgs e)
{
label1.Location = new Point(x, y - 50);
label1.Text = infos;
base.Opacity = 0.5;//设置窗体透明度
myHook.InsertHook();//安装钩子,记录输入锁屏密码
}
private void Frm_LScreen_MouseMove(object sender, MouseEventArgs e)
{
Cursor.Clip = new Rectangle(x, y, size.Width, size.Height);//设置鼠标指针的边界
}
private void Frm_LScreen_MouseClick(object sender, MouseEventArgs e)
{
Frm_UnLock frm_UnLock = new Frm_UnLock();
frm_UnLock.x = x;
frm_UnLock.y = y;
frm_UnLock.infos = infos;
frm_UnLock.pwd = pwd;
Operator.listforms.Add(frm_UnLock);
frm_UnLock.ShowDialog();
}
private void timer1_Tick(object sender, EventArgs e)
{
Process[] processes = Process.GetProcesses();//获取运行的所有进程名
foreach(Process p in processes)
{
try
{
if(p.ProcessName.ToLower().Trim()=="taskmgr")
{
p.Kill();//停止进程
Cursor.Clip = new Rectangle(x, y, size.Width, size.Height);
return;
}
}
catch
{
return;
}
}
}
private void Frm_LScreen_FormClosing(object sender, FormClosingEventArgs e)
{
myHook.UnInsertHook();//卸载钩子,解锁屏幕
timer1.Stop();
}
- 窗体3:解锁界面

csharp
#region 公共变量
public int x;
public int y;
public string infos;
public string pwd;
#endregion
private void Frm_UnLock_Load(object sender, EventArgs e)
{
this.TopMost = true;
this.Location=new Point(x, y);
label1.Text = infos;
}
private void button1_Click(object sender, EventArgs e)
{
if(textBox1.Text==pwd)
{
foreach(Form item in Operator.listforms)
{
item.Close();
item.Dispose();
}
this.Close();
}
else
{
label1.Text = "密码输入错误,请重新输入";
}
}
private void button2_Click(object sender, EventArgs e)
{
this.TopMost=false;
this.Close();
}