我正在使用下面的代码尝试获得操作系统范围的键盘输入,但没有成功:
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class InterceptKeys
{
private const int WH_KEYBOARD_LL = 13;
private const int WM_KEYDOWN = 0x0100;
private static LowLevelKeyboardProc _proc = HookCallback;
private static IntPtr _hookID = IntPtr.Zero;
public static void Main()
{
_hookID = SetHook(_proc);
while(true)
continue;
}
private static IntPtr SetHook(LowLevelKeyboardProc proc)
{
using (Process curProcess = Process.GetCurrentProcess())
using (ProcessModule curModule = curProcess.MainModule)
{
return SetWindowsHookEx(WH_KEYBOARD_LL, proc,
GetModuleHandle(curModule.ModuleName), 0);
}
}
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
private static IntPtr HookCallback(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0 && wParam == (IntPtr)WM_KEYDOWN)
{
int vkCode = Marshal.ReadInt32(lParam);
Console.WriteLine(vkCode);
}
return CallNextHookEx(_hookID, nCode, wParam, lParam);
}
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
}
HookCallback没有被调用。我怀疑它只是试图监听一个不存在的表单,而不是在系统范围内运行。
3条答案
按热度按时间rryofs0p1#
低级Windows钩子内部使用Windows消息传递。调用
SetWindowsHookEx
的线程必须在最后有消息循环,这允许调用HookCallback
函数。在C++中,消息循环如下所示:找到
GetMessage
、TranslateMessage
、DispatchMessage
和MSG
的所有必需的PInvoke定义,将此代码转换为C#并将其放置在while(true)
中,而不是无限循环中。您可以在PInvoke.Net中找到所有这些内容,另请参阅Microsoft论坛讨论:未调用控制台键盘挂钩
https://social.msdn.microsoft.com/Forums/vstudio/en-US/ed5be22c-cef8-4615-a625-d05caf113afc/console-keyboard-hook-not-getting-called?forum=csharpgeneral
xn1cxnb42#
我显然很晚了,但只是希望我能帮助(如果操作员还没有得到他/她需要的帮助),所以我张贴我的答案。
MSDN文档中指出,当您要设置系统范围的钩子时,必须给予hMod参数提供
DLL的句柄,该DLL包含lpfn参数所指向的挂接过程
以及
如果dwThreadId参数为零或指定由其他进程创建的线程的标识符,则lpfn参数必须指向DLL中的挂接过程
但是,看看这个:
设置窗口挂接Ex(2,kbdHookProc,获取模块句柄(“用户32”),0)
kbdHookProc是我的C# winforms应用程序中的一个函数,但是我在hMod参数中给出的值是通过GetModuleHandle加载user32.dll获得的hinstance。我正在使用键盘钩子(WH_KEYBOARD)来监视capslock、numlock和scroll lock键的锁定。不要问我为什么这样做,它是否有效,或者为什么有效,因为我不知道,但是,是的,它有效!
vwhgwdsa3#
完整的答案;
正如Alex所说,您需要一个消息循环来处理Windows消息并调用钩子,
我在这里使用一个单独的线程以避免阻塞主线程。
问题中的
InterceptKeys
类不需要修改;