我正在开发多选题考试系统,需要禁用所有键盘,仅使用鼠标单击即可,但是我遇到了这个问题
对类型为垃圾回收的委托进行了回调 '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);
}
答案 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;
}
}