摘要:C# 全域鍵盤掛鉤(Global Keyboard Hook)範例
C# 全域鍵盤掛鉤(Global Keyboard Hook)範例
上一篇的鍵盤掛鉤範例所 設置的 hook 是 WH_KEYBOARD,其鍵盤攔截的有效範圍僅限於該應用程式。如果你需要無時無刻攔截到特定按鍵(不管目前作用中的視窗是不是你的應用程式都要攔 到),則必須設置全域掛鉤(global hook),其對應的 hook 常數是 WH_KEYBOARD_LL(數值為 13,最後的 LL 是 Low Level 的縮寫)。
以下是範例原始碼:
1 using System;
2 using System.ComponentModel;
3 using System.Windows.Forms;
4 using System.Diagnostics;
5 using System.Runtime.InteropServices;
6
7 namespace KeyboardHook
8 {
9 public partial class Form1 : Form
10 {
11 public Form1()
12 {
13 InitializeComponent();
14 }
15
16 const int WH_KEYBOARD_LL = 13;
17
18 public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);
19
20 private static int m_HookHandle = 0; // Hook handle
21 private HookProc m_KbdHookProc; // 鍵盤掛鉤函式指標
22
23 [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
24 private static extern IntPtr GetModuleHandle(string lpModuleName);
25
26 // 設置掛鉤.
27 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
28 public static extern int SetWindowsHookEx(int idHook, HookProc lpfn, IntPtr hInstance, int threadId);
29
30 // 將之前設置的掛鉤移除。記得在應用程式結束前呼叫此函式.
31 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
32 public static extern bool UnhookWindowsHookEx(int idHook);
33
34 // 呼叫下一個掛鉤處理常式(若不這麼做,會令其他掛鉤處理常式失效).
35 [DllImport("user32.dll", CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)]
36 public static extern int CallNextHookEx(int idHook, int nCode, IntPtr wParam, IntPtr lParam);
37
38 private void button2_Click(object sender, EventArgs e)
39 {
40 if (m_HookHandle == 0)
41 {
42 using (Process curProcess = Process.GetCurrentProcess())
43 using (ProcessModule curModule = curProcess.MainModule)
44 {
45 m_KbdHookProc = new HookProc(Form1.KeyboardHookProc);
46
47 m_HookHandle = SetWindowsHookEx(WH_KEYBOARD_LL, m_KbdHookProc,
48 GetModuleHandle(curModule.ModuleName), 0);
49 }
50
51 if (m_HookHandle == 0)
52 {
53 MessageBox.Show("呼叫 SetWindowsHookEx 失敗!");
54 return;
55 }
56 button2.Text = "解除低階鍵盤掛鉤";
57 }
58 else
59 {
60 bool ret = UnhookWindowsHookEx(m_HookHandle);
61 if (ret == false)
62 {
63 MessageBox.Show("呼叫 UnhookWindowsHookEx 失敗!");
64 return;
65 }
66 m_HookHandle = 0;
67 button2.Text = "設置低階鍵盤掛鉤";
68 }
69 }
70
71 public static int KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
72 {
73 // 跟上一個範例相同,略。
105 }
106
107 }
108 }
NOTE:
- 執行此範例時,按下按鈕完成鍵盤掛鉤的設置後,可任意切換到別的應用程式。在任何地方按下的 Ctrl、Alt、Shift、和 F8 按鍵都會被攔到,你可以在 Visual Studio 的 Output 視窗中觀察攔截到按鍵時的輸出訊息。
- 全域的(低階)Windows 掛鉤通常必須實作成 Win32 DLL(.NET managed DLL 不行),但有兩個例外: WH_KEYBOARD_LL 和 WH_MOUSE_LL。也幸虧有這兩個特例,我們才能夠方便地在 .NET Windows Forms 應用程式中攔截全域的鍵盤事件。
- 注意 42~48 行,在設置全域鍵盤掛鉤,這裡傳入的是 module handle,而不像上一個範例傳入執行緒 ID。