问题描述
我的c#应用程序创建了用于处理键盘事件的键盘挂钩(许多读卡器,扫描仪和其他POS设备都模拟键盘).有时我的应用程序会创建没有错误的键盘挂钩,但不会触发事件,并且在处理时会引发异常:
My c# application creates keyboard hook for processing of keyboard events(many card readers, scanners and other POS equipment emulates keyboard).Sometimes my application creates keyboard hook without errors, but it's not firings events and on dispose throws exception:
其他日志条目是相同的错误,但可以说明
Other log entry is same error, but it tells about
我无法在我的PC上重现此问题,也不知道我应该调查或使用Google进行什么操作.我知道:
I can't reproduce this problem on my pc, and don't know what I should investigate or google.I know that:
- 使用x86操作系统的所有具有这种奇怪行为的客户端.
- Windows特权或权限可能存在一些问题.
- 有时会破裂(并非总是如此).
- 库面向.NET 4
- 应用程序针对.NET 4.5.1
- 编译平台:任何CPU
此外,我不太熟练使用非托管代码和Win API.我从某个线程获得了这段代码,并根据我的需要对其进行了修改,但具有较高的抽象水平.
Also, I'm not fluent with unmanaged code and win api. I got this code from some thread and modified it for my needs but on high level of abstraction.
挂钩ctor:
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);
推荐答案
如果在挂接过程中做错了事,Windows会在不通知您的情况下将您摘钩.
If you do something wrong in the hook proc Windows will unhook you without telling you.
- 在您的
LowLevelKeyboardProc
中,您没有检查nCode
!如果nCode
为< ;,则必须首先执行此操作.0您必须返回CallNextHookEx
,而无需进行其他任何处理. - 您不能在挂钩过程中花费太多时间.确切的限制未记录在AFAIK 中,并且可以通过注册表值更改.您应该针对<200毫秒才安全.
- In your
LowLevelKeyboardProc
you are not checkingnCode
! You must do that first and ifnCode
is < 0 you must return withCallNextHookEx
without any other processing. - You cannot spend too much time inside the hook proc. The exact limit is not documented AFAIK and can be changed by a registry value. You should aim for < 200ms to be safe.
您可以尝试在有问题的系统上设置/更改 LowLevelHooksTimeout
注册表值,以查看是否有帮助.
You could try setting/changing the LowLevelHooksTimeout
registry value on the problematic systems to see if that helps.
这篇关于SetWindowsHookEx挂钩停止工作的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!