You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C#检测特定进程时禁用指定按键失败:钩子设置问题排查

Fixing Low-Level Keyboard Hook Issues for Disabling Keys in Notepad.exe

Let's break down what's going wrong with your low-level keyboard hook implementation and fix it step by step. Your goal is to disable G, H, S keys only when Notepad is active, but several issues in your code are preventing this from working.

Key Issues in Your Code

  • Incorrect Module Handle for Hook: For WH_KEYBOARD_LL (low-level keyboard hook), you don't need to pass the target process (Notepad)'s module handle. This type of hook runs in the context of your own process, so you should use your application's module handle (or GetModuleHandle(null) which gets the current process's executable module).
  • Uninitialized ptrHook: You never assign the return value of SetWindowsHookEx to ptrHook in your Control method. This means CallNextHookEx and UnhookWindowsHookEx are using an uninitialized pointer, breaking the hook chain.
  • Thread Start Typo: cont.start() should be cont.Start() (C# is case-sensitive), which would cause a compile error.
  • No Check for Running Notepad: Process.GetProcessesByName("notepad")[0] will throw an exception if Notepad isn't running when your app starts.
  • Global Key Blocking: Your current code blocks the keys everywhere, not just in Notepad. You need to check if the active window belongs to a Notepad process before blocking keys.

Fixed Implementation

Here's the corrected code that addresses all these issues:

using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows.Forms;

namespace NotepadKeyBlocker
{
    public partial class Form1 : Form
    {
        [StructLayout(LayoutKind.Sequential)]
        private struct KBDLLHOOKSTRUCT
        {
            public Keys key;
            public int scanCode;
            public int flags;
            public int time;
            public IntPtr extra;
        }

        // Windows API imports
        private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern bool UnhookWindowsHookEx(IntPtr hhk);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        private static extern IntPtr GetModuleHandle(string lpModuleName);

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);

        // Global hook variables
        private static IntPtr _ptrHook = IntPtr.Zero;
        private static LowLevelKeyboardProc _keyboardProc;
        private const int WH_KEYBOARD_LL = 13;

        public Form1()
        {
            InitializeComponent();
            // Start the control thread with proper case and background flag
            Thread controlThread = new Thread(ControlNotepadKeys);
            controlThread.IsBackground = true; // Ensures thread exits when app closes
            controlThread.Start();
        }

        private void ControlNotepadKeys()
        {
            MessageBox.Show("Control thread started");

            // Wait for Notepad to launch (adjust polling interval as needed)
            Process notepadProcess = null;
            while (notepadProcess == null)
            {
                Process[] processes = Process.GetProcessesByName("notepad");
                if (processes.Length > 0)
                {
                    notepadProcess = processes[0];
                }
                Thread.Sleep(1000); // Check every second
            }

            // Initialize hook with current process's module handle
            _keyboardProc = new LowLevelKeyboardProc(CaptureKey);
            using (Process currentProcess = Process.GetCurrentProcess())
            using (ProcessModule currentModule = currentProcess.MainModule)
            {
                _ptrHook = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardProc, GetModuleHandle(currentModule.ModuleName), 0);
            }

            // Keep the thread alive to maintain the hook
            Application.Run();
        }

        private static IntPtr CaptureKey(int nCode, IntPtr wParam, IntPtr lParam)
        {
            if (nCode >= 0)
            {
                KBDLLHOOKSTRUCT keyInfo = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
                
                // Verify active window belongs to Notepad
                IntPtr foregroundWindow = GetForegroundWindow();
                GetWindowThreadProcessId(foregroundWindow, out uint processId);
                Process foregroundProcess = Process.GetProcessById((int)processId);

                if (foregroundProcess.ProcessName.Equals("notepad", StringComparison.OrdinalIgnoreCase))
                {
                    // Block specified keys
                    if (keyInfo.key == Keys.G || keyInfo.key == Keys.H || keyInfo.key == Keys.S)
                    {
                        return (IntPtr)1; // Return 1 to block the key event
                    }
                }
            }

            // Pass event to next hook in the chain if not blocked
            return CallNextHookEx(_ptrHook, nCode, wParam, lParam);
        }

        protected override void OnFormClosing(FormClosingEventArgs e)
        {
            base.OnFormClosing(e);
            // Clean up hook to prevent memory leaks
            if (_ptrHook != IntPtr.Zero)
            {
                UnhookWindowsHookEx(_ptrHook);
                _ptrHook = IntPtr.Zero;
            }
        }
    }
}

Key Fixes Explained

  1. Correct Hook Initialization: We now use the current process's module handle when setting the hook, which is required for WH_KEYBOARD_LL hooks.
  2. Saved Hook Handle: The return value from SetWindowsHookEx is stored in _ptrHook, ensuring CallNextHookEx and UnhookWindowsHookEx work as intended.
  3. Notepad Process Safety: We add a loop to wait for Notepad to launch, avoiding index-out-of-range exceptions if Notepad isn't running at app startup.
  4. Active Window Check: Keys are only blocked when the foreground window belongs to a Notepad process, so your regular system functionality remains unaffected.
  5. Proper Thread Management: The control thread is marked as background, and we explicitly unhook the keyboard when the form closes to clean up resources.
  6. Fixed Thread Start: controlThread.Start() uses correct C# casing to resolve compile errors.

内容的提问来源于stack exchange,提问作者Edson Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 15:12:41