Перехват клавиатуры не запускает события и выдает исключение win32 при удалении
Мое приложение С# создает клавиатурный хук для обработки событий клавиатуры (многие устройства чтения карт, сканеры и другое POS-оборудование эмулируют клавиатуру). Иногда мое приложение создает клавиатурный хук без ошибок, но оно не запускает события и при удалении выдает исключение:
System.ComponentModel.Win32Exception (0x80004005): не удалось удалить перехватчики клавиатуры для «приложения». Ошибка 1404: Недопустимый дескриптор хука
Другая запись в журнале - та же ошибка, но она говорит о
ERROR_NOT_ALL_ASSIGNED
Исходный код библиотеки и демонстрационного приложения.
Я не могу воспроизвести эту проблему на своем компьютере и не знаю, что мне следует изучить или поискать в Google. Я знаю это:
- Все клиенты с таким странным поведением используют операционную систему x86.
- Могут быть некоторые проблемы с привилегиями или правами Windows.
- Иногда ломается (не всегда).
- Библиотека нацелена на .NET 4
- Приложение нацелено на .NET 4.5.1
- Платформа компиляции: любой процессор
Кроме того, я плохо разбираюсь в неуправляемом коде и Win API. Я получил этот код из какого-то потока и изменил его для своих нужд, но на высоком уровне абстракции.
Крючок
public GlobalKeyboardHook()
{
_windowsHookHandle = IntPtr.Zero;
_user32LibraryHandle = IntPtr.Zero;
_hookProc = LowLevelKeyboardProc; // we must keep alive _hookProc, because GC is not aware about SetWindowsHookEx behaviour.
_user32LibraryHandle = LoadLibrary("User32");
if (_user32LibraryHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode,
$"Failed to load library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_windowsHookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, _user32LibraryHandle, 0);
if (_windowsHookHandle == IntPtr.Zero)
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode,
$"Failed to adjust keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
}
[DllImport("kernel32.dll")]
private static extern IntPtr LoadLibrary(string lpFileName);
[DllImport("USER32", SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hMod, int dwThreadId);
Крючок утилизировать:
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// because we can unhook only in the same thread, not in garbage collector thread
if (_windowsHookHandle != IntPtr.Zero)
{
if (!UnhookWindowsHookEx(_windowsHookHandle))
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode,
$"Failed to remove keyboard hooks for '{Process.GetCurrentProcess().ProcessName}'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_windowsHookHandle = IntPtr.Zero;
// ReSharper disable once DelegateSubtraction
_hookProc -= LowLevelKeyboardProc;
}
}
if (_user32LibraryHandle != IntPtr.Zero)
{
if (!FreeLibrary(_user32LibraryHandle)) // reduces reference to library by 1.
{
int errorCode = Marshal.GetLastWin32Error();
throw new Win32Exception(errorCode,
$"Failed to unload library 'User32.dll'. Error {errorCode}: {new Win32Exception(Marshal.GetLastWin32Error()).Message}.");
}
_user32LibraryHandle = IntPtr.Zero;
}
}
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
private static extern bool FreeLibrary(IntPtr hModule);
[DllImport("USER32", SetLastError = true)]
private static extern bool UnhookWindowsHookEx(IntPtr hHook);
SetWindowsHookEx(WH_KEYBOARD_LL, _hookProc, IntPtr.Zero, GetCurrentThreadId ());
, т.е. не передавать значение для module - person MickyD   schedule 09.02.2018