托管调试助手“ CallbackOnCollectedDelegate”:C#Windows窗体

时间:2019-01-28 09:41:34

标签: c# .net windows winforms

我正在开发多选题考试系统,需要禁用所有键盘,仅使用鼠标单击即可,但是我遇到了这个问题

  

对类型为垃圾回收的委托进行了回调   'UI!UI.Forms.frmExamHome + LowLevelKeyboardProcDelegate :: Invoke'。这个   可能导致应用程序崩溃,损坏和数据丢失。通过时   委托非托管代码,它们必须保持托管状态   应用程序,直到确保它们不会被调用为止。'

我的代码:

void wniDisable()
        {
           intLLKey = SetWindowsHookEx(WH_KEYBOARD_LL, LowLevelKeyboardProc, System.Runtime.InteropServices.Marshal.GetHINSTANCE(System.Reflection.Assembly.GetExecutingAssembly().GetModules()[0]).ToInt32(), 0);

        }
        [DllImport("user32", EntryPoint = "SetWindowsHookExA", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int SetWindowsHookEx(int idHook,  LowLevelKeyboardProcDelegate lpfn, int hMod, int dwThreadId);
        [DllImport("user32", EntryPoint = "UnhookWindowsHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int UnhookWindowsHookEx(int hHook);
        public delegate int LowLevelKeyboardProcDelegate(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        [DllImport("user32", EntryPoint = "CallNextHookEx", CharSet = CharSet.Ansi, SetLastError = true, ExactSpelling = true)]
        public static extern int CallNextHookEx(int hHook, int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam);
        public const int WH_KEYBOARD_LL = 13;

        /*code needed to disable start menu*/
        [DllImport("user32.dll")]
        private static extern int FindWindow(string className, string windowText);
        [DllImport("user32.dll")]
        private static extern int ShowWindow(int hwnd, int command);

        private const int SW_HIDE = 0;
        private const int SW_SHOW = 1;
        public struct KBDLLHOOKSTRUCT
        {
            public int vkCode;
            public int scanCode;
            public int flags;
            public int time;
            public int dwExtraInfo;
        }
        public static int intLLKey;

        public int LowLevelKeyboardProc(int nCode, int wParam, ref KBDLLHOOKSTRUCT lParam)
        {
            bool blnEat = false;

            switch (wParam)
            {
                case 256:
                case 257:
                case 260:
                case 261:
                    //Alt+Tab, Alt+Esc, Ctrl+Esc, Windows Key,
                    blnEat = ((lParam.vkCode == 9) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 32)) | ((lParam.vkCode == 27) && (lParam.flags == 0)) | ((lParam.vkCode == 91) && (lParam.flags == 1)) | ((lParam.vkCode == 92) && (lParam.flags == 1)) | ((lParam.vkCode == 73) && (lParam.flags == 0));
                    break;
            }

            if (blnEat == true)
            {
                return 1;
            }
            else
            {
                return CallNextHookEx(0, nCode, wParam, ref lParam);
            }
        }
        public void KillStartMenu()
        {
            int hwnd = FindWindow("Shell_TrayWnd", "");
            ShowWindow(hwnd, SW_HIDE);
        }

1 个答案:

答案 0 :(得分:0)

您需要将钩子委托存储为类成员,否则委托实例将是本地方法,并且在离开该方法后将被垃圾回收。

签出https://github.com/Alois-xx/etwcontroller/blob/master/ETWController/Hooking/Hooker.cs

用于工作样本。

   class Hooker : IDisposable
    {
        int MouseHookHandle;
        int KeyboardHookHandle;
        HookProc MouseHookGCRootedDelegate;
        HookProc KeyboardHookGCRootedDelegate;
..
    public Hooker()
        {
           // HookEvents.RegisterItself();
            MouseHookGCRootedDelegate = MouseHook;
            KeyboardHookGCRootedDelegate = KeyboardHook;
        }

        void HookKeyboard(bool bHook)
        {
            if (KeyboardHookHandle == 0 && bHook)
            {
                using (var mainMod = Process.GetCurrentProcess().MainModule)
                    KeyboardHookHandle = HookNativeDefinitions.SetWindowsHookEx(HookNativeDefinitions.WH_KEYBOARD_LL, KeyboardHookGCRootedDelegate, HookNativeDefinitions.GetModuleHandle(mainMod.ModuleName), 0);

                //If the SetWindowsHookEx function fails.
                if (KeyboardHookHandle == 0)
                {
                    System.Windows.MessageBox.Show("SetWindowsHookEx Failed " + new Win32Exception(Marshal.GetLastWin32Error()));
                    return;
                }
            }
            else if(bHook == false)
            {
                Debug.Print("Unhook keyboard");
                HookNativeDefinitions.UnhookWindowsHookEx(KeyboardHookHandle);
                KeyboardHookHandle = 0;
            }

        }