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

Win32 組合語言進階:超類別化 實作唯讀十六進位編輯框與 Tab 切換

     編輯:組合語言

超類別化 vs 子類別化

實作流程:建立 SUPEREDITCLASS (唯讀十六進位 + Tab 導航)

1. 取得 EDIT 類別資訊

.IF uMsg == WM_CREATE
  LOCAL wc:WNDCLASSEX
  MOV wc.cbSize, SIZEOF WNDCLASSEX
  INVOKE GetClassInfoEx, NULL, ADDR EditClass, ADDR wc
  ; wc 現在包含 EDIT 完整定義

2. 修改關鍵成員

PUSH wc.lpfnWndProc
POP  OldWndProc              ; 保存原始 EDIT WndProc
MOV  wc.lpfnWndProc, OFFSET EditWndProc  ; 掛上自訂程序
PUSH hInstance
POP  wc.hInstance            ; 必須設為本模組實例
MOV  wc.lpszClassName, OFFSET OurClass   ; 新類別名 "SUPEREDITCLASS"

3. 註冊新類別並批量建立控件

INVOKE RegisterClassEx, ADDR wc
XOR EBX, EBX
MOV EDI, 20
.WHILE EBX < 6
  INVOKE CreateWindowEx, WS_EX_CLIENTEDGE, ADDR OurClass, NULL, \
       WS_CHILD | WS_VISIBLE | WS_BORDER, \
       20, EDI, 300, 25, hWnd, EBX, hInstance, NULL
  MOV DWORD PTR [hwndEdit+4*EBX], EAX  ; 存入句柄陣列
  ADD EDI, 25
  INC EBX
.ENDW
INVOKE SetFocus, hwndEdit              ; 聚焦第一個

自訂視窗程序 EditWndProc 核心邏輯

字元過濾:只接受 0-9, A-F, a-f, Backspace

.IF uMsg == WM_CHAR
  MOV EAX, wParam
  .IF (AL >= '0' && AL <= '9') || (AL >= 'A' && AL <= 'F') || \
      (AL >= 'a' && AL <= 'f') || AL == VK_BACK
    .IF AL >= 'a' && AL <= 'f'
      SUB AL, 20h              ; 小寫轉大寫
    .ENDIF
    INVOKE CallWindowProc, OldWndProc, hEdit, uMsg, EAX, lParam
    RET
  .ENDIF
  ; 非法字元:直接丟棄,不轉發 → 不顯示
.ELSEIF uMsg == WM_KEYDOWN
  ...
.ELSE
  INVOKE CallWindowProc, OldWndProc, hEdit, uMsg, wParam, lParam
  RET
.ENDIF

Tab / Shift-Tab 導航實作 (集中式,無需逐個子類別化)

.ELSEIF uMsg == WM_KEYDOWN
  MOV EAX, wParam
  .IF AL == VK_RETURN
    INVOKE MessageBox, hEdit, ADDR Message, ADDR AppName, MB_OK|MB_ICONINFORMATION
    INVOKE SetFocus, hEdit
  .ELSEIF AL == VK_TAB
    INVOKE GetKeyState, VK_SHIFT
    TEST EAX, 80000000h
    .IF ZERO?                      ; 未按 Shift → 下一個
      INVOKE GetWindow, hEdit, GW_HWNDNEXT
      .IF EAX == NULL
        INVOKE GetWindow, hEdit, GW_HWNDFIRST
      .ENDIF
    .ELSE                          ; 按 Shift → 上一個
      INVOKE GetWindow, hEdit, GW_HWNDPREV
      .IF EAX == NULL
        INVOKE GetWindow, hEdit, GW_HWNDLAST
      .ENDIF
    .ENDIF
    INVOKE SetFocus, EAX
    XOR EAX, EAX
    RET
  .ELSE
    INVOKE CallWindowProc, OldWndProc, hEdit, uMsg, wParam, lParam
    RET
  .ENDIF

關鍵 API 說明

  • GetKeyState(VK_SHIFT):高位元組 Bit 7 = 1 表正按下
  • GetWindow(hWnd, GW_HWNDNEXT/PREV/FIRST/LAST):依 Z-order 遍歷同層視窗
  • SetFocus(hWnd):移動輸入焦點,觸發 WM_KILLFOCUS/SETFOCUS

超類別化優勢總結

  • **一次修改,處處生效**:6 個編輯框共用同一 EditWndProc,新增控件只需多一行 CreateWindowEx
  • **效能優於子類別化**:無額外 SetWindowLong 呼叫,視窗建立即具備目標行為
  • **原始行為完整保留**:透過 CallWindowProc 轉發未處理訊息,EDIT 原生功能 (複製/貼上/游標移動/選取) 全部正常
  • **Tab 導航集中實作**:對話框管理器自動處理 Tab,但一般視窗需自行實作;超類別化讓所有同類控件共享導航邏輯

適用場景擴展

  • 數值輸入框 (整數/浮點/範圍驗證)
  • IP 位址輸入框 (四段式自動跳欄)
  • 日期/時間輸入框 (格式強制、合法性檢查)
  • 密碼框 (字元遮罩、防拖曳/複製)
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved
特性子類別化超類別化
作用對象**已建立**的視窗實例**視窗類別** (註冊前)
適用場景少數現有控件修改行為大量建立具相同行為的新控件
步驟SetWindowLong(GWL_WNDPROC)GetClassInfoEx → 修改 WNDCLASSEX → RegisterClassEx → CreateWindowEx
原始 WndProc 保存SetWindowLong 返回值 / GetWindowLongGetClassInfoEx 取得的 WNDCLASSEX.lpfnWndProc