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

C 語言函數指針表驅動設計:消息映射、命令分發與 MFC 雛形實現

     編輯:關於C語言

一、核心思想:數據驅動控制流

將「消息 ID → 處理函數」映射表達為靜態數組,運行時查表分發,實現開閉原則:新增消息只需擴展表,核心分發邏輯不變。這正是 MFC 消息映射、Windows 內核 IRP 分發、嵌入式狀態機的核心模式。

二、基礎結構定義


#include <windows.h> // 類型定義

// 消息映射表項
typedef struct {
    UINT message;                    // 消息 ID
    LRESULT (*handler)(HWND, UINT, WPARAM, LPARAM); // 處理函數指針
} MSG_MAP_ENTRY;

// 宏:計算靜態數組元素個數
#define DIM(x) (sizeof(x) / sizeof((x)[0]))

三、消息映射表定義


// 窗口消息映射表
MSG_MAP_ENTRY g_msgMap[] = {
    { WM_CREATE,   OnCreate },
    { WM_PAINT,    OnPaint },
    { WM_SIZE,     OnSize },
    { WM_COMMAND,  OnCommand }, // 命令消息二次分發
    { WM_SETFOCUS, OnSetFocus },
    { WM_CLOSE,    OnClose },
    { WM_DESTROY,  OnDestroy },
    { 0, NULL } // 結束標記(可選)
};

// 命令消息映射表(WM_COMMAND 的 wParam 低字)
MSG_MAP_ENTRY g_cmdMap[] = {
    { IDM_ABOUT,   OnAbout },
    { IDM_OPEN,    OnFileOpen },
    { IDM_SAVEAS,  OnSaveAs },
    { 0, NULL }
};

四、核心分發函數


// 主窗口過程
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    for (int i = 0; g_msgMap[i].handler; ++i) {
        if (msg == g_msgMap[i].message)
            return g_msgMap[i].handler(hwnd, msg, wParam, lParam);
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

// WM_COMMAND 專用分發
LRESULT CALLBACK OnCommand(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) {
    UINT cmdId = LOWORD(wParam);
    for (int i = 0; g_cmdMap[i].handler; ++i) {
        if (cmdId == g_cmdMap[i].message)
            return g_cmdMap[i].handler(hwnd, msg, wParam, lParam);
    }
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

五、具體處理函數示例


LRESULT OnCreate(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    // 初始化資源
    return 0;
}
LRESULT OnPaint(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    PAINTSTRUCT ps; HDC hdc = BeginPaint(hwnd, &ps);
    TextOut(hdc, 10, 10, L"Hello, Table-Driven!", 20);
    EndPaint(hwnd, &ps);
    return 0;
}
LRESULT OnAbout(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    MessageBox(hwnd, L"Table-Driven Demo", L"About", MB_OK);
    return 0;
}
// ... 其他處理函數同理

六、進階擴展:動態註冊與優先級


typedef struct {
    UINT message;
    LRESULT (*handler)(HWND, UINT, WPARAM, LPARAM);
    int priority; // 數值越大越優先
    void* userData; // 攜帶上下文
} DynMsgEntry;

#define MAX_DYN_HANDLERS 64
static DynMsgEntry g_dynHandlers[MAX_DYN_HANDLERS];
static int g_dynCount = 0;

BOOL RegisterMsgHandler(UINT msg, LRESULT (*fn)(HWND,UINT,WPARAM,LPARAM), int priority, void* data) {
    if (g_dynCount >= MAX_DYN_HANDLERS) return FALSE;
    g_dynHandlers[g_dynCount++] = (DynMsgEntry){msg, fn, priority, data};
    // 可按 priority 排序,或查找時遍歷選擇最高優先級
    return TRUE;
}

LRESULT CALLBACK DynamicWndProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
    LRESULT (*bestHandler)(HWND,UINT,WPARAM,LPARAM) = NULL;
    int bestPri = -1;
    for (int i = 0; i < g_dynCount; ++i) {
        if (g_dynHandlers[i].message == msg && g_dynHandlers[i].priority > bestPri) {
            bestPri = g_dynHandlers[i].priority;
            bestHandler = g_dynHandlers[i].handler;
        }
    }
    if (bestHandler) return bestHandler(hwnd, msg, wp, lp);
    return DefWindowProc(hwnd, msg, wp, lp);
}

七、MFC 實現對比(概念映射)

本文模式MFC 對應說明
MSG_MAP_ENTRYAFX_MSGMAP_ENTRY結構體定義基本一致
靜態數組 g_msgMap[]BEGIN_MESSAGE_MAP / ON_MESSAGE / END_MESSAGE_MAP宏展開生成靜態數組
WndProc 循環查表CWnd::WindowProc -> OnWndMsg -> AfxFindMessageEntryMFC 額外支援命令路由、消息反射
命令二次分發 OnCommandON_COMMAND / ON_BN_CLICKEDMFC 用 CCmdTarget 鏈路由

八、應用場景擴展

  1. 嵌入式協議解析:命令碼 → 解析函數表。
  2. 遊戲事件系統:事件類型 → 监聽器列表(觀察者模式表驅動版)。
  3. HTTP 路由:路徑模式 → 處理器函數(如 nginx、libevent)。
  4. 狀態機:state × event → action + next_state 二維表。

九、總結

表驅動設計將控制邏輯數據化,以極小的運行時開銷換取極大的靈活性。從 Windows 窗口過程到現代 Web 框架路由,均是此模式的變體。掌握其核心——靜態表定義 + 通用分發循環 + 可擴展註冊機制,即可在任何 C/C++ 專案中構建清晰、可維護的分發層。

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