首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 設定 Windows Hook 捕捉滑鼠事件:執行緒專用 Hook 實作全攻略

     編輯:關於C語言

前言:何謂 Windows Hook?

Windows Hook(鉤子)是一種強大的機制,允許應用程式攔截並處理系統訊息,如鍵盤、滑鼠事件。透過 SetWindowsHookEx API,我們可以將自訂的 Hook 程序掛入鉤子鏈,實現全域或執行緒專用的事件監控。

本文以滑鼠 Hook(WH_MOUSE)為例,示範如何在 Visual C# .NET 中建立特定執行緒的 Hook,並在表單標題列即時顯示滑鼠座標。

核心 API 與 P/Invoke 宣告

所有 Win32 API 呼叫皆需透過 System.Runtime.InteropServices 進行平台呼叫(P/Invoke)。以下為必要的委派、結構與外部方法宣告:

1. 委派與常數

public delegate int HookProc(int nCode, IntPtr wParam, IntPtr lParam);

public const int WH_MOUSE = 7; // 滑鼠 Hook 類型
static int hHook = 0; // Hook 控制碼
HookProc MouseHookProcedure;

2. 結構體對應

[StructLayout(LayoutKind.Sequential)]
public class POINT { public int x; public int y; }

[StructLayout(LayoutKind.Sequential)]
public class MouseHookStruct
{
    public POINT pt;
    public int hwnd;
    public int wHitTestCode;
    public int dwExtraInfo;
}

3. 導入 User32.dll 函式

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

實作步驟:建立執行緒專用滑鼠 Hook

步驟 1:建立 Windows Forms 專案

  • 專案類型:Visual C# Projects → Windows Application
  • 專案名稱:ThreadSpecificMouseHook
  • 預設表單:Form1

步驟 2:在 Form1.cs 加入命名空間

using System.Runtime.InteropServices;

步驟 3:按鈕點擊事件——安裝/移除 Hook

private void button1_Click(object sender, EventArgs e)
{
    if (hHook == 0) // 安裝 Hook
    {
        MouseHookProcedure = new HookProc(Form1.MouseHookProc);
        hHook = SetWindowsHookEx(WH_MOUSE, MouseHookProcedure, (IntPtr)0, AppDomain.GetCurrentThreadId());

        if (hHook == 0)
        {
            MessageBox.Show("SetWindowsHookEx Failed");
            return;
        }
        button1.Text = "UnHook Windows Hook";
    }
    else // 移除 Hook
    {
        bool ret = UnhookWindowsHookEx(hHook);
        if (!ret) MessageBox.Show("UnhookWindowsHookEx Failed");
        hHook = 0;
        button1.Text = "Set Windows Hook";
        this.Text = "Mouse Hook";
    }
}

關鍵點:threadId 使用 AppDomain.GetCurrentThreadId() 限定為當前執行緒,實現「執行緒專用 Hook」。

步驟 4:Hook 回呼函式——處理滑鼠事件

public static int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    if (nCode < 0) return CallNextHookEx(hHook, nCode, wParam, lParam);

    // 將非受控記憶體封送為 Managed 結構
    MouseHookStruct info = (MouseHookStruct)Marshal.PtrToStructure(lParam, typeof(MouseHookStruct));

    string caption = $"x = {info.pt.x}  y = {info.pt.y}";
    Form.ActiveForm.Text = caption; // 更新標題列

    return CallNextHookEx(hHook, nCode, wParam, lParam); // 傳遞給下一個 Hook
}

執行與驗證

  1. 按 F5 執行專案。
  2. 點擊表單上的按鈕,標題變為「UnHook Windows Hook」,表示 Hook 已生效。
  3. 在表單上移動滑鼠,標題列即時顯示座標。
  4. 再次點擊按鈕,Hook 移除,標題恢復預設。

重要限制:.NET 不支援全域 Hook

無法在 .NET Framework 中實作全域 Hook。
全域 Hook 需要原生 DLL 匯出函式以注入其他處理序,而 Managed 程式碼的函式指標是動態建立的 Proxy,無法提供穩定的匯出位址。因此,若需全域鍵盤/滑鼠監控,必須撰寫 C++ DLL 並透過 P/Invoke 呼叫。

完整程式碼結構

using System;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace ThreadSpecificMouseHook
{
    public class Form1 : Form
    {
        // ... 委派、常數、結構、DllImport 宣告 ...

        private Button button1;

        public Form1()
        {
            button1 = new Button { Text = "Set Windows Hook", Dock = DockStyle.Top };
            button1.Click += button1_Click;
            Controls.Add(button1);
        }

        // ... button1_Click, MouseHookProc ...
    }
}

總結

透過 SetWindowsHookEx 與 P/Invoke,C# 可輕鬆實作執行緒專用 Hook,監控特定執行緒的滑鼠、鍵盤事件。雖然 .NET 原生不支援全域 Hook,但針對單一應用程式內的事件攔截,此方案已足夠強大且易於維護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved