我一直在用C#写一个低级的键盘钩子。按下任意键后,效果很好,执行了回调方法,但是如果我尝试在该回调方法中使用诸如Marshal.ReadInt32
或Marshal.Copy
之类的代码,则我的代码将停止在我使用的位置执行Marshal
类,就像使用Marshal
类一样,它就像一个return语句。
private static IntPtr OnKeyEvent(int code, IntPtr wParam, IntPtr lParam)
{
Console.WriteLine("Before");
int wP = Marshal.ReadInt32(wParam);
Console.WriteLine("After");
return CallNextHookEx(IntPtr.Zero, code, wParam, lParam);
}
其结果是:
如果我注释掉Marshal.ReadInt32行:
那是为什么?
答案 0 :(得分:3)
使用此:
int wP = wParam.ToInt32();
似乎您正在为WH_KEYBOARD_LL或WH_KEYBOARD安装键盘钩。在这种情况下,wParam值包含WM_KEYDOWN(0x0100)或WM_KEYUP(0x0101)-如您所说。您可以从lParam获取虚拟键码-应该是有效的Pointer。因此,您可以将封送功能用于lParam:
int keyCode = Marshal.ReadInt32(lParam);
答案 1 :(得分:1)
您可以检查此操作的正确方式。
https://github.com/Alois-xx/etwcontroller/blob/master/ETWController/Hooking/Hooker.cs
public int KeyboardHook(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
var keyboardData = (HookNativeDefinitions.KeyboardHookStruct)Marshal.PtrToStructure(lParam, typeof(HookNativeDefinitions.KeyboardHookStruct));
unchecked
{
// wParam is WM_KEYDOWN, WM_KEYUP, WM_SYSKEYDOWN, or WM_SYSKEYUP
int wInt = wParam.ToInt32();
var key = KeyInterop.KeyFromVirtualKey((int)keyboardData.vkCode);
if (wInt == WM.KEYDOWN || wInt == WM.SYSKEYDOWN && OnKeyDown != null)
{
OnKeyDown?.Invoke(key);
}
else
{
}
}
}
return HookNativeDefinitions.CallNextHookEx(MouseHookHandle, nCode, wParam, lParam);
}
您的示例崩溃是因为您尝试取消引用例如(无效*)100 == WM_KEYDOWN用于各种窗口消息。您需要将wParam转换为整数,然后将lParam转换为KeyboardStruct结构,从中获取实际的键码。