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

Win32 組語教學:子視窗控件的建立與訊息處理

     編輯:組合語言

前言

在 Windows 程式設計中,子視窗控件是構建使用者介面的基石。按鈕、編輯框、核取方塊、下拉式清單等常見元件,皆屬於預先定義好的子視窗類別。善用這些控件,不僅能大幅減輕程式設計師的負擔,更能確保介面行為符合 Windows 標準規範。本文將深入探討如何在組語中建立子視窗控件、處理其通知訊息,並透過完整範例示範編輯框與按鈕的互動操作。

核心概念:預定義視窗類別與控件 ID

Windows 系統內建了數種預定義視窗類別(如 button、edit、static、listbox 等),開發者無需自行註冊,直接呼叫 CreateWindow 或 CreateWindowEx 並指定類別名稱即可建立。每個控件必須擁有唯一的控件 ID(在 CreateWindowEx 的 hMenu 參數傳入),以便父視窗在接收 WM_COMMAND 訊息時識別事件來源。

控件建立的最佳時機:WM_CREATE

慣例上,我們在父視窗的 WM_CREATE 訊息處理程序中建立子控件。此時父視窗已存在,且系統尚未進入訊息迴圈,確保控件在使用者互動前已就緒。建立時可指定 WS_CHILD、WS_VISIBLE 等基本樣式,以及控件專屬的擴充樣式(如按鈕的 BS_DEFPUSHBUTTON、編輯框的 ES_AUTOHSCROLL)。

訊息辨識:WM_COMMAND 參數解析

子控件狀態改變時,會向父視窗發送 WM_COMMAND。關鍵在於正確解讀 wParam 與 lParam:

  • 低位字 (LOWORD wParam):控件 ID 或選單項目 ID
  • 高位字 (HIWORD wParam):通知碼(如 BN_CLICKED、EN_CHANGE)
  • lParam:子控件的視窗句柄(若為選單項目則為 0)

透過判斷 lParam 是否為 0,可區分事件來源是選單還是控件。

完整範例:編輯框與按鈕互動

以下 MASM 範例建立一個主視窗,內含編輯框與按鈕,並提供選單項目操作編輯框內容:

.386
.model flat,stdcall
option casemap:none
WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib

.data
ClassName db "SimpleWinClass",0
AppName db "Our First Window",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "My First Button",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?)

.const
ButtonID equ 1
EditID equ 2
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4

.code
start:
invoke GetModuleHandle, NULL
mov hInstance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProcess,eax

WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
LOCAL wc:WNDCLASSEX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.cbSize,SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hInst
pop wc.hInstance
mov wc.hbrBackground,COLOR_BTNFACE+1
mov wc.lpszMenuName,OFFSET MenuName
mov wc.lpszClassName,OFFSET ClassName
invoke LoadIcon,NULL,IDI_APPLICATION
mov wc.hIcon,eax
mov wc.hIconSm,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterClassEx, addr wc
invoke CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName, \
ADDR AppName, WS_OVERLAPPEDWINDOW,\
CW_USEDEFAULT, CW_USEDEFAULT,\
300,200,NULL,NULL, hInst,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.WHILE TRUE
invoke GetMessage, ADDR msg,NULL,0,0
.BREAK .IF (!eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
.ENDW
mov eax,msg.wParam
ret
WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg==WM_DESTROY
invoke PostQuitMessage,NULL
.ELSEIF uMsg==WM_CREATE
invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,\
WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or\
ES_AUTOHSCROLL,\
50,35,200,25,hWnd,EditID,hInstance,NULL
mov hwndEdit,eax
invoke SetFocus, hwndEdit
invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,\
WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,\
75,70,140,25,hWnd,ButtonID,hInstance,NULL
mov hwndButton,eax
.ELSEIF uMsg==WM_COMMAND
mov eax,wParam
.IF lParam==0
.IF ax==IDM_HELLO
invoke SetWindowText,hwndEdit,ADDR TestString
.ELSEIF ax==IDM_CLEAR
invoke SetWindowText,hwndEdit,NULL
.ELSEIF ax==IDM_GETTEXT
invoke GetWindowText,hwndEdit,ADDR buffer,512
invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
.ELSE
invoke DestroyWindow,hWnd
.ENDIF
.ELSE
.IF ax==ButtonID
shr eax,16
.IF ax==BN_CLICKED
invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
.ENDIF
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc,hWnd,uMsg,wParam,lParam
ret
.ENDIF
xor eax,eax
ret
WndProc endp
end start

關鍵技巧:轉發訊息簡化程式碼

範例中按鈕被點擊時,並未重複撰寫取得文字並顯示的邏輯,而是呼叫 SendMessage(hWnd, WM_COMMAND, IDM_GETTEXT, 0) 將訊息轉發給自身視窗程序,由選單項目 IDM_GETTEXT 的處理分支統一執行。這種「訊息轉發」技巧能有效避免程式碼重複,提升維護性。

別忘了 TranslateMessage

訊息迴圈中必須呼叫 TranslateMessage,否則編輯框無法接收鍵盤字元輸入(WM_CHAR)。此函式將虛擬鍵碼訊息(WM_KEYDOWN)轉換為字元訊息,是啟用文字輸入的關鍵。

總結

掌握子視窗控件的建立、唯一 ID 分配、WM_COMMAND 參數解析,以及善用 SetWindowText/GetWindowText 等通用 API,即可在組語中靈活構建豐富的視窗介面。下一課將進一步探討對話方塊如何自動處理鍵盤導航與控件管理。

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