從零建立一個最基本的 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
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:大/小圖示,此處用系統預設應用程式圖示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_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX
INVOKE ShowWindow, hwnd, CmdShow ; CmdShow = SW_SHOWDEFAULT
INVOKE UpdateWindow, hwnd ; 立即發送 WM_PAINT
.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,**不**直接呼叫 ExitProcessDefWindowProc,否則視窗基本行為 (移動、調整大小、系統選單) 失效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 |