C#上位机启动后锁定Win键,防止意外退出

156 阅读5分钟

前言

工业自动化和生产环境中,上位机程序的稳定运行至关重要。

操作人员的误操作,如意外按下Win键,可能会导致程序退出或界面切换,从而影响生产效率甚至引发安全问题。为了避免这种情况,许多企业需要在程序启动后禁用Win键,确保操作人员专注于当前任务。

本文将介绍如何在C#上位机程序中实现启动后锁定Win键,防止意外退出,确保程序的稳定运行。

键盘消息拦截与钩子 (Hook) 实现思路

在Windows系统中,所有键盘操作都是基于消息机制的。每当按下或释放一个键时,系统会生成相应的消息并发送给当前活动的应用程序。

因此,要实现特定按键或功能的屏蔽,最直接的方法是通过拦截这些消息来阻止它们到达目标应用程序。

实现思路:使用钩子 (Hook)

为了实现上位机程序启动后禁用Win组合键的功能,我们可以采用钩子 (Hook) 技术。

钩子是一种拦截并处理系统消息的机制。通过设置全局或线程级别的键盘钩子,可以在消息传递到目标应用程序之前对其进行检查和过滤。

具体来说,在程序启动时,我们可以安装一个低级键盘钩子(Low-Level Keyboard Hook),它能够捕获所有键盘输入事件,包括Win组合键。一旦检测到需要屏蔽的按键组合,就直接丢弃该消息,从而防止其影响系统的正常操作。

这种方法不仅适用于禁用Win组合键,还可以灵活地扩展以支持其他类型的按键控制需求。此前在讲解扫码枪集成时也提及了类似的消息拦截技术,证明了钩子在处理特定输入场景下的有效性和实用性。

钩子原理

钩子是操作系统消息处理的一种机制。通过钩子,应用程序可以安装一个钩子回调过程让系统调用,从而监视系统中的消息队列。在这些消息到达目标窗口之前对这些消息进行处理。

钩子特点

钩子函数会降低操作系统的性能,因为它增加系统处理每一个消息的开销。

操作系统支持多种类型的钩子,每种类型都提供了它特有的消息处理机制。

对于每种类型的钩子,系统都维护一个各自独立的钩子链,钩子链是一个指向用户提供的回调函数钩子过程的链表指针。

钩子尽量避免大量使用,对于一个钩子,一般是需要的时候安装,使用完成后,尽快卸载。

代码实现

下面就直接贴代码了,主要是在键盘钩子处理那里加了一些需要截获的消息。

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(@"SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem"true);  
                if (key == null)//如果该项不存在的话,则创建该项  
                    key = Registry.CurrentUser.CreateSubKey(@"SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem");  
                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(@"SoftwareMicrosoftWindowsCurrentVersionPoliciesSystem"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 1if (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();  
    }  
}  

钩子使用

使用方法也很简单,在窗体初始化的时候,采用无边框并最大化窗体,然后启动钩子。

private Hook hook;  
public FrmMain()  
{  
    InitializeComponent();  

    this.FormBorderStyle = FormBorderStyle.None;  
    this.WindowState = 
    FormWindowState.Maximized;  
    this.TopMost = true;  
    hook = new Hook();  
    hook.Start();  
    this.FormClosing += 
    new FormClosingEventHandler
    (FrmMain_FormClosing);  
}  

在窗体关闭事件里关闭钩子,钩子使用一定要及时关闭。

private void FrmMain_FormClosing
(object sender, FormClosingEventArgs e)  
{  
    hook.Close();  
}  

这样运行程序后,如果没有提供关闭程序的入门,似乎就只能重启系统了,大家测试时要注意保存电脑现有程序及文件。

总结

通过在C#上位机程序中实现启动后锁定Win键,我们可以有效防止操作人员因误操作导致的程序意外退出,从而保障程序的稳定运行和操作的连续性。

本文介绍了具体的实现方法,通过全局钩子监听键盘事件并阻止Win键的按下。这种方法不仅简单高效,而且能够显著提升上位机程序在工业环境中的可靠性和安全性。通过这些技术手段,企业可以更好地管理生产流程,减少因误操作带来的潜在风险。

最后

如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。

也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!

优秀是一种习惯,欢迎大家留言学习!

作者:dotNet工控上位机

出处:mp.weixin.qq.com/s/9selRYddIYITfJYwDF1Xxg

声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!