public override void StartHook() { if (_started) { return; } _windowsKeyboardHookHandle = IntPtr.Zero; _keyboardHookProc = LowLevelKeyboardProc; // we must keep alive proc, because GC is not aware about SetWindowsHookEx behaviour. If you remove this, the program will crash when the garbage collector reaps it. _user32LibraryHandle = IntPtr.Zero; _user32LibraryHandle = NativeApi.LoadLibrary("User32"); if (_user32LibraryHandle == IntPtr.Zero) { var errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, $"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}."); } _windowsKeyboardHookHandle = NativeApi.SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardHookProc, _user32LibraryHandle, 0); if (_windowsKeyboardHookHandle == IntPtr.Zero) { var errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, $"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}."); } }
public override void StopHook() { if (!_started) { return; } if (_windowsKeyboardHookHandle == IntPtr.Zero) { return; } if (!NativeApi.UnhookWindowsHookEx(_windowsKeyboardHookHandle)) { var errorCode = Marshal.GetLastWin32Error(); throw new Win32Exception(errorCode, $"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}."); } _windowsKeyboardHookHandle = IntPtr.Zero; // ReSharper disable once DelegateSubtraction _keyboardHookProc -= LowLevelKeyboardProc; }