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

Win32 組語教學:建立基本視窗程式完整流程

     編輯:組合語言

前言

Windows GUI 程式開發需遵循嚴格規範:註冊視窗類別、建立視窗、進入訊息迴圈、處理視窗程序。本文以最精簡的「建立一個可顯示的視窗」為例,逐行解析 MASM32 組語實作,說明各 API 用途、結構體填寫細節、訊息迴圈運作機制,並提供可直接編譯執行的完整範本程式碼。

建立視窗的標準步驟

  1. 取得模組實例句柄 GetModuleHandle
  2. 取得命令列參數 GetCommandLine (可選)
  3. 填寫 WNDCLASSEX 結構並註冊視窗類別 RegisterClassEx
  4. 建立視窗 CreateWindowEx
  5. 顯示視窗 ShowWindow
  6. 更新客戶區 UpdateWindow
  7. 進入訊息迴圈:GetMessage → TranslateMessage → DispatchMessage
  8. 視窗程序處理 WM_DESTROY → PostQuitMessage 結束迴圈

關鍵結構體:WNDCLASSEX 詳細說明

WNDCLASSEX STRUCT DWORD
    cbSize        DWORD ?  ; 結構大小,必須填 SIZEOF WNDCLASSEX
    style         DWORD ?  ; 類別樣式,如 CS_HREDRAW | CS_VREDRAW
    lpfnWndProc   DWORD ?  ; 視窗程序位址 (OFFSET WndProc)
    cbClsExtra    DWORD ?  ; 類別額外記憶體位元組數
    cbWndExtra    DWORD ?  ; 視窗實例額外記憶體位元組數
    hInstance     DWORD ?  ; 模組實例句柄
    hIcon         DWORD ?  ; 大圖示句柄
    hCursor       DWORD ?  ; 游標句柄
    hbrBackground DWORD ?  ; 背景筆刷句柄 (COLOR_WINDOW+1 等系統色)
    lpszMenuName  DWORD ?  ; 選單資源名稱指標
    lpszClassName DWORD ?  ; 類別名稱指標 (ASCIIZ)
    hIconSm       DWORD ?  ; 小圖示句柄
WNDCLASSEX ENDS

必填欄位:cbSize、lpfnWndProc、hInstance、lpszClassName、hbrBackground (否則背景不重繪)。

CreateWindowEx 12 參數詳細對照

參數範例值說明
dwExStyleNULL擴充視窗樣式 (如 WS_EX_CLIENTEDGE 立體邊框)
lpClassNameADDR ClassName已註冊類別名稱
lpWindowNameADDR AppName標題列文字
dwStyleWS_OVERLAPPEDWINDOW視窗樣式 (含標題列、系統選單、最大/最小/關閉鈕)
X, YCW_USEDEFAULT左上角座標,交由系統決定
nWidth, nHeightCW_USEDEFAULT寬高,交由系統決定
hWndParentNULL父視窗句柄,NULL 為最上層視窗
hMenuNULL選單句柄 (若類別已指定選單則忽略)
hInstancehInst模組實例句柄
lpParamNULL建立參數 (WM_CREATE 的 lParam 傳遞)

訊息迴圈與 TranslateMessage 的關鍵作用

.WHILE TRUE
invoke GetMessage, ADDR msg, NULL, 0, 0
.BREAK .IF (!eax)          ; WM_QUIT 時 eax=0 跳出
invoke TranslateMessage, ADDR msg  ; 虛擬鍵碼 → 字元訊息 (WM_CHAR)
invoke DispatchMessage, ADDR msg   ; 分派至視窗程序
.ENDW
  • GetMessage 會阻塞等待訊息,系統可調度其他執行緒/進程 (協同多工基礎)。
  • TranslateMessage 將 WM_KEYDOWN/WM_KEYUP 轉換為 WM_CHAR,編輯框、文字輸入必須呼叫此函式,否則無法接收字元。
  • DispatchMessage 依訊息中的 hwnd 找到視窗程序並呼叫。

視窗程序:最小實作

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg == WM_DESTROY
    invoke PostQuitMessage, NULL  ; 發送 WM_QUIT 結束迴圈
.ELSE
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam  ; 預設處理
    ret
.ENDIF
xor eax, eax
ret
WndProc endp
  • 僅處理 WM_DESTROY,其他訊息交給 DefWindowProc (預設:繪製邊框、處理移動/縮放、系統選單等)。
  • 處理完自訂訊息需 xor eax, eax 回傳 0,未處理訊息必須呼叫 DefWindowProc 並回傳其結果。

完整可編譯範本程式碼

.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

.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

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_WINDOW+1
mov wc.lpszMenuName, NULL
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, NULL, ADDR ClassName, ADDR AppName, \
    WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, \
    CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
mov hwnd, eax
invoke ShowWindow, hwnd, CmdShow
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
.ELSE
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret
.ENDIF
xor eax, eax
ret
WndProc endp
end start

編譯連結指令 (MASM32)

ml /c /coff /Cp /nologo template.asm
link /SUBSYSTEM:WINDOWS /LIBPATH:"\masm32\lib" template.obj /OUT:template.exe

常見錯誤與除錯提示

現象原因修正
視窗不顯示未呼叫 ShowWindow 或 UpdateWindow確認兩者皆在 CreateWindowEx 後呼叫
無法輸入文字訊息迴圈缺少 TranslateMessage加入 TranslateMessage 於 GetMessage 之後
程式無法結束WM_DESTROY 未呼叫 PostQuitMessage在 WM_DESTROY 分支加入 PostQuitMessage
連結錯誤 LNK2001缺少 includelib user32.lib kernel32.lib於 .asm 開頭加入對應 includelib
類別註冊失敗cbSize 未正確設定mov wc.cbSize, SIZEOF WNDCLASSEX

總結

掌握上述流程與範本,即擁有了所有 Win32 組語 GUI 專案的起點。後續功能 (選單、控件、對話方塊、繪圖、檔案 I/O) 皆在這個框架上擴充。建議將此範本存為 skeleton.asm,新專案直接複製修改。

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