2015-09-21 2 views
2

При обсуждении перехвата клавиатуры this article получает много бросков.C# Клавиатура выталкивает клавиатуру System.NullReferenceException

Так я привязал класс, который он предложил:

using System; 
    using System.Collections.Generic; 
    using System.Text; 
    using System.Runtime.InteropServices; 
    using System.Windows.Forms; 

    namespace Utilities { 
    /// <summary> 
    /// A class that manages a global low level keyboard hook 
    /// </summary> 
    class globalKeyboardHook { 
    #region Constant, Structure and Delegate Definitions 
    /// <summary> 
    /// defines the callback type for the hook 
    /// </summary> 
    public delegate int keyboardHookProc(int code, int wParam, ref keyboardHookStruct lParam); 

    public struct keyboardHookStruct { 
     public int vkCode; 
     public int scanCode; 
     public int flags; 
     public int time; 
     public int dwExtraInfo; 
    } 

    const int WH_KEYBOARD_LL = 13; 
    const int WM_KEYDOWN = 0x100; 
    const int WM_KEYUP = 0x101; 
    const int WM_SYSKEYDOWN = 0x104; 
    const int WM_SYSKEYUP = 0x105; 
    #endregion 

    #region Instance Variables 
    /// <summary> 
    /// The collections of keys to watch for 
    /// </summary> 
    public List<Keys> HookedKeys = new List<Keys>(); 
    /// <summary> 
    /// Handle to the hook, need this to unhook and call the next hook 
    /// </summary> 
    IntPtr hhook = IntPtr.Zero; 
    #endregion 

    #region Events 
    /// <summary> 
    /// Occurs when one of the hooked keys is pressed 
    /// </summary> 
    public event KeyEventHandler KeyDown; 
    /// <summary> 
    /// Occurs when one of the hooked keys is released 
    /// </summary> 
    public event KeyEventHandler KeyUp; 
    #endregion 

    #region Constructors and Destructors 
    /// <summary> 
    /// Initializes a new instance of the <see cref="globalKeyboardHook"/> class and installs the keyboard hook. 
    /// </summary> 
    public globalKeyboardHook() { 
     hook(); 
    } 

    /// <summary> 
    /// Releases unmanaged resources and performs other cleanup operations before the 
    /// <see cref="globalKeyboardHook"/> is reclaimed by garbage collection and uninstalls the keyboard hook. 
    /// </summary> 
    ~globalKeyboardHook() { 
     unhook(); 
    } 
    #endregion 

    #region Public Methods 
    /// <summary> 
    /// Installs the global hook 
    /// </summary> 
    public void hook() { 
     IntPtr hInstance = LoadLibrary("User32"); 
     hhook = SetWindowsHookEx(WH_KEYBOARD_LL, hookProc, hInstance, 0); 
    } 

    /// <summary> 
    /// Uninstalls the global hook 
    /// </summary> 
    public void unhook() { 
     UnhookWindowsHookEx(hhook); 
    } 

    /// <summary> 
    /// The callback for the keyboard hook 
    /// </summary> 
    /// <param name="code">The hook code, if it isn't >= 0, the function shouldn't do anyting</param> 
    /// <param name="wParam">The event type</param> 
    /// <param name="lParam">The keyhook event information</param> 
    /// <returns></returns> 
    public int hookProc(int code, int wParam, ref keyboardHookStruct lParam) { 
     if (code >= 0) { 
      Keys key = (Keys)lParam.vkCode; 
      if (HookedKeys.Contains(key)) { 
       KeyEventArgs kea = new KeyEventArgs(key); 
       if ((wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN) && (KeyDown != null)) { 
        KeyDown(this, kea) ; 
       } else if ((wParam == WM_KEYUP || wParam == WM_SYSKEYUP) && (KeyUp != null)) { 
        KeyUp(this, kea); 
       } 
       if (kea.Handled) 
        return 1; 
      } 
     } 
     return CallNextHookEx(hhook, code, wParam, ref lParam); 
    } 
    #endregion 

    #region DLL imports 
    /// <summary> 
    /// Sets the windows hook, do the desired event, one of hInstance or threadId must be non-null 
    /// </summary> 
    /// <param name="idHook">The id of the event you want to hook</param> 
    /// <param name="callback">The callback.</param> 
    /// <param name="hInstance">The handle you want to attach the event to, can be null</param> 
    /// <param name="threadId">The thread you want to attach the event to, can be null</param> 
    /// <returns>a handle to the desired hook</returns> 
    [DllImport("user32.dll")] 
    static extern IntPtr SetWindowsHookEx(int idHook, keyboardHookProc callback, IntPtr hInstance, uint threadId); 

    /// <summary> 
    /// Unhooks the windows hook. 
    /// </summary> 
    /// <param name="hInstance">The hook handle that was returned from SetWindowsHookEx</param> 
    /// <returns>True if successful, false otherwise</returns> 
    [DllImport("user32.dll")] 
    static extern bool UnhookWindowsHookEx(IntPtr hInstance); 

    /// <summary> 
    /// Calls the next hook. 
    /// </summary> 
    /// <param name="idHook">The hook id</param> 
    /// <param name="nCode">The hook code</param> 
    /// <param name="wParam">The wparam.</param> 
    /// <param name="lParam">The lparam.</param> 
    /// <returns></returns> 
    [DllImport("user32.dll")] 
    static extern int CallNextHookEx(IntPtr idHook, int nCode, int wParam, ref keyboardHookStruct lParam); 

    /// <summary> 
    /// Loads the library. 
    /// </summary> 
    /// <param name="lpFileName">Name of the library</param> 
    /// <returns>A handle to the library</returns> 
    [DllImport("kernel32.dll")] 
    static extern IntPtr LoadLibrary(string lpFileName); 
    #endregion 
} 
} 

Он работает немного, но после того, как с помощью компьютера на некоторое время, он будет бросать System.NullReferenceException на случайном нажатии клавиши. Особенно вокруг ключевых комбинаций.

Что может быть причиной этого и как его можно исправить?

EDIT: Это код, я использую, чтобы начать с крючка:

globalKeyboardHook globalKeyboardHook = new globalKeyboardHook(); 
private void Form1_Load(object sender, EventArgs e) 
{ 
    globalKeyboardHook.KeyDown += gkh_KeyDown; 
    globalKeyboardHook.KeyUp += gkh_KeyUp; 
    globalKeyboardHook.hook(); 
} 

И это полная ошибка я получаю:

Необработанное исключение типа «System .NullReferenceException ' произошло в System.Windows.Forms.dll Дополнительная информация: Ссылка на объект не установлена ​​в экземпляр объекта.

+2

вы можете показать нам код, который вы используете, чтобы назвать это, а также точная ошибку вашей получать? – Nikerym

+1

Как я помню, многие проблемы были из-за GC, процедуры должны быть защищены KeepAlive – Spawn

+0

Я не вижу, где вы работаете с клавишами Ctrl, Alt и Shift. Другой вариант - программа async, где вы можете отпереть ключи после (event! = Null) проверок, но до запуска делегата события. – Oxoron

ответ

1

Попробуйте использовать поле для хранения обратного вызова, чтобы избежать делегата собираемыхов с помощью ОГО:

private static keyboardHookProc callback; 

public void hook() 
{ 
    callback = new keyboardHookProc(hookProc); 
    var hhook = SetWindowsHookEx(1, callback, IntPtr.Zero, 0); 
} 
+0

Замена кода крюка на это, похоже, не позволяет подключить какие-либо ключи. – Andy

Смежные вопросы