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

Win32 組合語言教學:建立標準視窗完整範例(RegisterClassEx / CreateWindowEx / 訊息迴路)

     編輯:組合語言

教學目標

從零建立一個最基本的 Win32 GUI 程式:註冊視窗類別、建立重疊視窗、顯示與更新、進入訊息迴路、處理 WM_DESTROY 退出。完整展示 WNDCLASSEX、CreateWindowEx 參數細節、GetMessage/TranslateMessage/DispatchMessage 迴路機制。

程式架構總覽

.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE \MASM32\INCLUDE\WINDOWS.INC
INCLUDE \MASM32\INCLUDE\USER32.INC
INCLUDELIB \MASM32\LIB\USER32.LIB
INCLUDE \MASM32\INCLUDE\KERNEL32.INC
INCLUDELIB \MASM32\LIB\KERNEL32.LIB

WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD

.DATA
  ClassName DB "SimpleWinClass",0
  AppName   DB "Our First Window",0
.DATA?
  hInstance HINSTANCE ?
  CommandLine LPSTR ?

.CODE
START:
  INVOKE GetModuleHandle, NULL
  MOV hInstance, EAX
  INVOKE GetCommandLine
  MOV CommandLine, EAX
  INVOKE WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
  INVOKE ExitProcess, EAX
  ...
END START

WinMain 核心流程

1. 填寫 WNDCLASSEX

LOCAL wc:WNDCLASSEX
MOV wc.cbSize, SIZEOF WNDCLASSEX
MOV wc.style, CS_HREDRAW OR CS_VREDRAW
MOV wc.lpfnWndProc, OFFSET WndProc
MOV wc.cbClsExtra, 0
MOV wc.cbWndExtra, 0
PUSH hInstance
POP wc.hInstance
MOV wc.hbrBackground, COLOR_WINDOW+1
MOV wc.lpszMenuName, 0
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

關鍵成員說明

  • cbSize:必須設為 SIZEOF WNDCLASSEX,否則註冊失敗
  • style:CS_HREDRAW|CS_VREDRAW 視窗水平/垂直尺寸改變時完整重繪
  • lpfnWndProc:視窗程序入口點,**最關鍵**成員
  • hbrBackground:COLOR_WINDOW+1 使用系統預設視窗背景色筆刷
  • hIcon/hIconSm:大/小圖示,此處用系統預設應用程式圖示

2. 建立視窗

INVOKE CreateWindowEx,
  0,                      ; dwExStyle: 無擴充風格
  ADDR ClassName,         ; lpClassName: 註冊類別名
  ADDR AppName,           ; lpWindowName: 標題列文字
  WS_OVERLAPPEDWINDOW,    ; dwStyle: 標準重疊視窗 (含標題、系統選單、最大/小/關閉)
  CW_USEDEFAULT,          ; X: 系統決定位置
  CW_USEDEFAULT,          ; Y:
  CW_USEDEFAULT,          ; nWidth: 系統決定大小
  CW_USEDEFAULT,          ; nHeight:
  NULL,                   ; hWndParent: 無父視窗
  NULL,                   ; hMenu: 使用類別預設選單 (無)
  hInstance,              ; hInstance: 應用程式實例
  NULL                    ; lpParam: 無建立參數
MOV hwnd, EAX

WS_OVERLAPPEDWINDOW 拆解

WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX

3. 顯示與更新

INVOKE ShowWindow, hwnd, CmdShow   ; CmdShow = SW_SHOWDEFAULT
INVOKE UpdateWindow, hwnd          ; 立即發送 WM_PAINT

4. 訊息迴路

.WHILE TRUE
  INVOKE GetMessage, ADDR msg, NULL, 0, 0
  .BREAK .IF !EAX                  ; GetMessage 返回 0 (WM_QUIT) 跳出
  INVOKE TranslateMessage, ADDR msg
  INVOKE DispatchMessage, ADDR msg
.ENDW
MOV EAX, msg.wParam                ; 退出碼
RET

視窗程序

WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
  .IF uMsg == WM_DESTROY
    INVOKE PostQuitMessage, 0      ; 發送 WM_QUIT 結束訊息迴路
  .ELSE
    INVOKE DefWindowProc, hWnd, uMsg, wParam, lParam
    RET
  .ENDIF
  XOR EAX, EAX
  RET
WndProc ENDP

關鍵點

  • WM_DESTROY 只負責發送 WM_QUIT,**不**直接呼叫 ExitProcess
  • 未處理訊息**必須**轉交 DefWindowProc,否則視窗基本行為 (移動、調整大小、系統選單) 失效
  • 返回值置 0 ( XOR EAX,EAX ) 符合大多數訊息的預期

建置指令

ML /c /coff /Cp WIN1.ASM
LINK /SUBSYSTEM:WINDOWS /LIBPATH:C:\MASM32\LIB WIN1.OBJ

常見錯誤排查

現象可能原因
編譯通過但執行無視窗未呼叫 ShowWindow / UpdateWindow、或 WNDCLASSEX.cbSize 錯誤
視窗一閃即關訊息迴路缺少 TranslateMessage/DispatchMessage、或 WndProc 未處理 WM_DESTROY
標題列亂碼字串未以 0 結尾、或編碼不符 (ANSI vs Unicode)
連結錯誤 LNK2001缺少 INCLUDELIB USER32.LIB / KERNEL32.LIB
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved