WndProc 視窗處理函數【一】

前言

在C# 中,WndProc 是一個用於處理 Windows 消息的函數,通常在創建自定義控件或重寫窗口行為時使用。

它是 Windows 消息循環的核心部分之一。

  • WndProc 是 Window Procedure(視窗處理函數)的縮寫。
  • 它是 Windows 系統用來 傳遞和處理視窗訊息(Messages)的主要機制。
  • 每個視窗(或控制項)都可以有一個視窗過程,用來接收並處理如滑鼠點擊、鍵盤按鍵、繪圖等事件

下面會有幾個繼承自 Form 或 Control 的Class中重寫 WndProc 的方法



1. 攔截關閉訊息 (WM_CLOSE)

protected override void WndProc(ref Message m)
{
    const int WM_CLOSE = 0x0010;

    if (m.Msg == WM_CLOSE)
    {
        DialogResult result = MessageBox.Show("確定要關閉應用程式嗎?", "提示", MessageBoxButtons.YesNo);
        if (result == DialogResult.No)
            return; // 阻止關閉
    }

    base.WndProc(ref m);
}



2. 禁用最大化按鈕 (WM_SYSCOMMAND)

protected override void WndProc(ref Message m)
{
    const int WM_SYSCOMMAND = 0x0112;
    const int SC_MAXIMIZE = 0xF030;

    if (m.Msg == WM_SYSCOMMAND && m.WParam.ToInt32() == SC_MAXIMIZE)
    {
        // 阻止最大化
        return;
    }

    base.WndProc(ref m);
}



3. 處理熱鍵 (WM_HOTKEY)

[DllImport("user32.dll")]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, int fsModifiers, int vk);

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    RegisterHotKey(this.Handle, 1, 0x0002, (int)Keys.F12); // Ctrl + F12
}

protected override void WndProc(ref Message m)
{
    const int WM_HOTKEY = 0x0312;

    if (m.Msg == WM_HOTKEY)
    {
        int id = m.WParam.ToInt32();
        if (id == 1)
        {
            MessageBox.Show("熱鍵 Ctrl+F12 被觸發!");
        }
    }

    base.WndProc(ref m);
}



4. 攔截鼠標右鍵 (WM_RBUTTONDOWN)

protected override void WndProc(ref Message m)
{
    const int WM_RBUTTONDOWN = 0x0204;

    if (m.Msg == WM_RBUTTONDOWN)
    {
        MessageBox.Show("右鍵點擊被攔截!");
        return;
    }

    base.WndProc(ref m);
}



5. 攔截鍵盤輸入 (WM_KEYDOWN)

protected override void WndProc(ref Message m)
{
    const int WM_KEYDOWN = 0x0100;

    if (m.Msg == WM_KEYDOWN)
    {
        Keys key = (Keys)m.WParam.ToInt32();
        if (key == Keys.Escape)
        {
            MessageBox.Show("你按下了 ESC 鍵!");
            return;
        }
    }

    base.WndProc(ref m);
}



6. 顯示滑鼠移動位置 (WM_MOUSEMOVE)

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

public class MouseMoveForm : Form
{
    private const int WM_MOUSEMOVE = 0x0200;

    protected override void WndProc(ref Message m)
    {
        if (m.Msg == WM_MOUSEMOVE)
        {
            // 從 LParam 取得 X 和 Y 座標(低位為 X,高位為 Y)
            int x = m.LParam.ToInt32() & 0xFFFF;
            int y = (m.LParam.ToInt32() >> 16) & 0xFFFF;

            this.Text = $"Mouse Position: ({x}, {y})"; // 顯示在標題列
        }

        base.WndProc(ref m);
    }
}
  • WM_MOUSEMOVE:當滑鼠在視窗上移動時會觸發。
  • LParam:包含滑鼠座標,低 16 位是 X,高 16 位是 Y。
  • this.Text:即視窗的標題,我們用它即時顯示滑鼠座標。


  • 建議總是呼叫 base.WndProc(ref m); 以保證其他消息能正常處理。
  • 大部分WM_* 常量可以在 WinUser.h 裡查到

WinUser.h(Windows SDK)

這個檔案是 Windows SDK 中的一部分,通常會隨著 Visual Studio 安裝或 Windows 開發環境提供。

  • 檔案位置
  • C:\Program Files (x86)\Windows Kits\10\Include\<SDK 版本號>\um\WinUser.h
    #define WM_PAINT 0x000F
    #define WM_KEYDOWN 0x0100
    #define WM_MOUSEMOVE 0x0200
    

在 C# 裡你不能直接使用這些 C 巨集(宏),但可以自己定義這些常數:

private const int WM_PAINT = 0x000F;
private const int WM_KEYDOWN = 0x0100;
private const int WM_MOUSEMOVE = 0x0200;

留言