77namespace RT . Util
88{
99 /// <summary>Manages a global low-level keyboard hook.</summary>
10- public sealed class GlobalKeyboardListener
10+ public sealed class GlobalKeyboardListener : IDisposable
1111 {
1212 /// <summary>The collections of keys to watch for. This is ignored if <see cref="HookAllKeys" /> is set to true.</summary>
1313 public List < Keys > HookedKeys { get { return _hookedKeys ; } }
@@ -24,45 +24,41 @@ public sealed class GlobalKeyboardListener
2424 /// <summary>Current state of each modifier key.</summary>
2525 private bool _ctrl , _alt , _shift , _win ;
2626
27- #region Events
2827 /// <summary>Occurs when one of the hooked keys is pressed.</summary>
2928 public event GlobalKeyEventHandler KeyDown ;
3029 /// <summary>Occurs when one of the hooked keys is released.</summary>
3130 public event GlobalKeyEventHandler KeyUp ;
32- #endregion
3331
34- #region Constructors and Destructors
32+ /// <summary>Keeps the managed delegate referenced so that the garbage collector doesn’t collect it.</summary>
33+ private WinAPI . KeyboardHookProc _hook ;
34+
3535 /// <summary>
3636 /// Initializes a new instance of the <see cref="GlobalKeyboardListener" /> class and installs the keyboard hook.</summary>
3737 public GlobalKeyboardListener ( )
3838 {
39- hook ( ) ;
39+ IntPtr hInstance = WinAPI . LoadLibrary ( "User32" ) ;
40+ _hook = hookProc ; // don’t remove this or the garbage collector will collect it while the global hook still tries to access it
41+ _hHook = WinAPI . SetWindowsHookEx ( WinAPI . WH_KEYBOARD_LL , _hook , IntPtr . Zero , 0 ) ;
4042 }
4143
44+ private bool _disposed = false ;
45+
4246 /// <summary>
4347 /// Releases unmanaged resources and performs other cleanup operations before the <see
4448 /// cref="GlobalKeyboardListener" /> is reclaimed by garbage collection and uninstalls the keyboard hook.</summary>
4549 ~ GlobalKeyboardListener ( )
4650 {
47- unhook ( ) ;
48- }
49- #endregion
50-
51- private WinAPI . KeyboardHookProc _hook ;
52-
53- #region Public Methods
54- /// <summary>Installs the global hook</summary>
55- private void hook ( )
56- {
57- IntPtr hInstance = WinAPI . LoadLibrary ( "User32" ) ;
58- _hook = new WinAPI . KeyboardHookProc ( hookProc ) ;
59- _hHook = WinAPI . SetWindowsHookEx ( WinAPI . WH_KEYBOARD_LL , _hook , hInstance , 0 ) ;
51+ Dispose ( ) ;
6052 }
6153
62- /// <summary>Uninstalls the global hook</summary>
63- private void unhook ( )
54+ /// <summary>Unregisters the hook and disposes the object. </summary>
55+ public void Dispose ( )
6456 {
65- WinAPI . UnhookWindowsHookEx ( _hHook ) ;
57+ if ( ! _disposed )
58+ {
59+ _disposed = true ;
60+ WinAPI . UnhookWindowsHookEx ( _hHook ) ;
61+ }
6662 }
6763
6864 /// <summary>
@@ -139,7 +135,6 @@ private int hookProc(int code, int wParam, ref WinAPI.KeyboardHookStruct lParam)
139135 }
140136 return WinAPI . CallNextHookEx ( _hHook , code , wParam , ref lParam ) ;
141137 }
142- #endregion
143138 }
144139
145140 /// <summary>Encapsulates the current state of modifier keys.</summary>
0 commit comments