2013-03-21 139 views
0

我需要捕獲全局鍵盤消息,所以我使用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

一般來說,使用熱鍵而不是掛鉤更安全。爲什麼你需要一個鉤子而不是一個熱鍵有沒有特別的理由? – Guido 2013-03-21 12:52:08

+0

Yeap,我需要捕捉每一個輸入,因爲它將成爲一個「記錄器」。 – UnknitSplash 2013-03-21 12:59:51

+0

如果這是你的mainform的代碼,那麼你不應該註冊事件處理程序嗎? – Guido 2013-03-22 08:37:12

回答

0

問題出在「調試」功能。 Form tempForm = Form.ActiveForm;

1

幸得喬恩這裏:

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); 

對其他簽名也應做類似的更改。 雖然Microsoft本身具有以int形式顯示SetwindowsHookEx作爲返回類型的資源(https://support.microsoft.com/en-us/kb/318804),但您絕不應輕易用其他類型替代'IntPtr'。在這種情況下,'int'僅在32位操作系統中等同於'IntPtr'。在64位平臺上,IntPtr是64位,而'int'只保留在32位上,從而打開一整罐蠕蟲。使用'int'最糟糕的一個方面是,如果SetWindowsHookEx的返回值不能適應它,那麼你很可能最終會出現一個錯位的int句柄(它很少見但並不是不可思議的)。

這意味着如果您的應用程序的生命週期超過了您解除掛鉤的位置(而不是解除掛鉤的調用將始終工作以開始......),那麼您最終可能會凍結鼠標和/或鍵盤,直到主機進程被終止。大多數人都會在這一刻重新啓動機器,並完全處置您的應用程序。所有這些「鍵盤/鼠標凍結」的事情都會發生,因爲未配置的鉤子需要到達主機應用程序的消息泵,顯然這不會發生,因爲它所屬的組件已經在處理過程中失效了 - wooohoo!

TL; DR:注意您正在使用的p/invoke方法和特別是IntPtrs的簽名。