我需要捕获全局键盘消息,因此我将SetWindowsHookEx()与WH_KEYBOARD_LL一起使用。但它仅在应用程序处于焦点时才起作用,并且不会全局触发回调。几乎相同的代码适用于mouse_LL(使用其他结构和等等)请帮忙!
public const int WH_KEYBOARD_LL = 13;
public const int VK_INSERT = 0x2D;
public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
HookProc KeyboardHookProcedure;
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn,
IntPtr hInstance, int threadId);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern bool UnhookWindowsHookEx(int idHook);
[DllImport("user32.dll", CharSet = CharSet.Auto,
CallingConvention = CallingConvention.StdCall)]
public static extern int CallNextHookEx(int idHook, int nCode,
IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[StructLayout(LayoutKind.Sequential)]
private struct KBDLLHOOKSTRUCT
{
public uint vkCode;
public uint scanCode;
public uint flags;
public uint time;
public IntPtr dxExtraInfo;
}
private void SetHookKeyboard()
{
if (kHook == 0)
{
KeyboardHookLL();
//If the SetWindowsHookEx function fails.
if (kHook == 0)
{
MessageBox.Show("SetWindowsHookEx Failed");
return;
}
button1.Text = "UnHook Windows Hook";
}
else
{
bool ret = UnhookWindowsHookEx(kHook);
//If the UnhookWindowsHookEx function fails.
if (ret == false)
{
MessageBox.Show("UnhookWindowsHookEx Failed");
return;
}
kHook = 0;
this.Text = "Keyboard Hook";
}
}
private void KeyboardHookLL()
{
KeyboardHookProcedure = new HookProc(MainForm.KeyboardHookProc);
kHook = SetWindowsHookEx(WH_KEYBOARD_LL, KeyboardHookProcedure, GetModuleHandle("user32"), 0);
}
public static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
KBDLLHOOKSTRUCT MyKeyboardHookStruct = (KBDLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(KBDLLHOOKSTRUCT));
if (nCode < 0)
{
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
else
{
Form tempForm = Form.ActiveForm;
tempForm.Text = MyKeyboardHookStruct.vkCode.ToString();
if (MyKeyboardHookStruct.vkCode == VK_INSERT)
{
MainForm.botAlive = false;
MessageBox.Show(MainForm.botAlive.ToString());
}
return CallNextHookEx(hHook, nCode, wParam, lParam);
}
}
答案 0 :(得分:1)
此处有人向Jon致信:
int vs IntPtr when you have a handle?
我知道这是一个很老的帖子而且我有点离题了,但是我注意到原始代码中有一个险恶的缺点,它可以在适当的时候扭转你并且非常糟糕(我知道它在我的情况下做了):
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
更优选的是:
[DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
static extern IntPtr SetWindowsHookEx(HookType hookType, HookProc lpfn, IntPtr hMod, uint dwThreadId);
也应对其他签名进行类似的更改。 即使微软本身拥有显示SetwindowsHookEx并且int为返回类型(https://support.microsoft.com/en-us/kb/318804)的资源,您也不应该轻易地将'IntPtr'替换为其他类型。在这种情况下,'int'仅相当于32位操作系统中的'IntPtr'。在64位平台中,'IntPtr'是64位,而'int'只保持32位,这就打开了一大堆蠕虫。使用'int'的最糟糕的一个方面是,如果SetWindowsHookEx的返回值不适合它,那么你很可能最终会得到一个错误的int-handle(它很少但不可思议)。
这意味着,如果你的应用程序的生命周期延长到你取消挂钩/丢弃挂钩的程度(而不是unhook调用将开始工作......)那么你可能最终会冻结鼠标和/或键盘完全被移除,直到主机进程被终止。大多数人只需在此时重新启动计算机并完全处理您的应用程序。所有这些“键盘/鼠标冻结”的事情都发生了,因为未使用的钩子需要到达主机应用程序的消息泵,这显然不可能发生,因为它所属的组件在处理期间已经破灭 - 哇哇!
TL; DR:注意你正在使用的p / invoke方法的签名和特别是IntPtrs。
答案 1 :(得分:0)
问题在于“调试”功能。 表格tempForm = Form.ActiveForm;