本文為系列第三篇,詳細說明如何使用 SetWindowsHookEx 安裝低階鍵盤(WH_KEYBOARD_LL)與滑鼠(WH_MOUSE_LL)全域鉤子,涵蓋委托建立、模組控制代碼取得、錯誤處理與回滾機制。
public void Start(bool installMouseHook, bool installKeyboardHook)
{
// 安裝滑鼠鉤子
if (hMouseHook == IntPtr.Zero && installMouseHook)
{
MouseHookProcedure = new HookProc(MouseHookProc);
hMouseHook = SetWindowsHookEx(
WH_MOUSE_LL,
MouseHookProcedure,
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
0);
if (hMouseHook == IntPtr.Zero)
{
int err = Marshal.GetLastWin32Error();
Stop(true, false, false); // 回滾
throw new Win32Exception(err);
}
}
// 安裝鍵盤鉤子
if (hKeyboardHook == IntPtr.Zero && installKeyboardHook)
{
KeyboardHookProcedure = new HookProc(KeyboardHookProc);
hKeyboardHook = SetWindowsHookEx(
WH_KEYBOARD_LL,
KeyboardHookProcedure,
Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]),
0);
if (hKeyboardHook == IntPtr.Zero)
{
int err = Marshal.GetLastWin32Error();
Stop(false, true, false); // 回滾
throw new Win32Exception(err);
}
}
}
HookProc 委托必須保持存活(存為欄位),否則 GC 回收導致回呼失效。Marshal.GetHINSTANCE(Assembly.GetExecutingAssembly().GetModules()[0]) 取得目前組件的 HINSTANCE,全域鉤子必須在 DLL 中,但 .NET 組件即視為 DLL。Marshal.GetLastWin32Error() 必須緊跟 SetWindowsHookEx 之後。private delegate IntPtr HookProc(int nCode, IntPtr wParam, IntPtr lParam);
private IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
if (nCode >= 0)
{
// 處理鍵盤訊息,觸發事件通知 UI
// ...
}
return CallNextHookEx(hKeyboardHook, nCode, wParam, lParam);
}
nCode < 0:不可處理,直接傳遞下一個鉤子。CallNextHookEx:將訊息傳遞給鉤子鏈中的下一個處理器,**必須呼叫**,否則阻斷系統訊息流。LL)不需在獨立 DLL,直接在進程中實作即可。掌握 SetWindowsHookEx 正確安裝流程、委托生命週期管理與失敗回滾機制,是構建穩定全域鉤子應用的關鍵。下一篇將介紹滑鼠鉤子結構體定義與 SendInput 相關 API 封裝。