| 項目 | Win16 (舊) | Win32 (現行) |
| 記憶體模式 | 分段 (Small/Medium/Large/Huge) | FLAT (平坦):單一 4GB 線性空間 |
| 段暫存器 | CS/DS/SS/ES 需管理 | 任意段暫存器可址 4GB,無需切換 |
| 參數傳遞 | PASCAL (左→右,被調用者清堆疊) | STDCALL (右→左,被調用者清堆疊) |
| 呼叫慣例例外 | C (右→左,呼叫者清堆疊) | wsprintf 仍用 C 慣例 (可變參數) |
標準程式框架模板
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
.DATA
; 已初始化資料
.DATA?
; 未初始化資料 (僅佔 .bss,不增大 exe 體積)
.CONST
; 唯讀常數
.CODE
; 程式碼
START:
; 入口點
...
END START
偽指令詳細說明
.386 / .486 / .586 (.P 後綴)
.386:指令集基準 80386,最安全相容
.386P:允許特權指令 (LGIDT, LIDT, MOV CRx 等),核心/驅動開發用
- 應用層程式**一律用無 P 版本**
.MODEL FLAT, STDCALL
FLAT:告知 MASM 使用 32 位平坦模式,段屬性預設 32 位
STDCALL:設定預設呼叫慣例,影響 PROC、INVOKE、PROTO 代碼生成
.DATA / .DATA? / .CONST / .CODE
- 這是 **Section (區段)** 而非 Segment (段)。Win32 只有兩種區段屬性:
- CODE:可讀可執行 (RX)
- DATA:可讀可寫 (RW),.DATA? 對應 .bss (僅記錄大小)
.CONST:唯讀資料區,違規寫入觸發存取違規 (GPF)
標號與 END
MYLABEL:
...
END MYLABEL
END 後的標號指定**程式進入點** (Entry Point),連結器會設定 AddressOfEntryPoint
- 若省略
END 參數,進入點預設為第一個 .CODE 區段的第一條指令
Win32 程式設計鐵律
- 保存非易失性暫存器:
EBX, ESI, EDI, EBP, ESP (及段暫存器) 在 Callback/視窗程序中**必須**保存/還原。Windows 內部高頻使用這些暫存器,不檢查是否被改動。
- EAX/ECX/EDX 為易失性:API 呼叫後內容不保證保留,勿假設值不變。
- 堆疊 4 位元組對齊:STDCALL 要求呼叫前 ESP % 4 == 0,MASM 自動處理但手工 PUSH/POP 需注意。
- 回調函數原型:
WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM — 參數順序、型別**必須**與 Windows 期望完全一致。
從 DOS 移植的常見誤區
| DOS 習慣 | Win32 正確做法 |
| 直接寫記憶體 B800h 輸出文字 | GDI/TextOut/DrawText 繪製於 DC |
| INT 21h/INT 10h 服務 | Win32 API (KERNEL32/USER32/GDI32) |
| 自行管理記憶體區段 | VirtualAlloc/HeapAlloc/GlobalAlloc |
| CLI/STI 控制中斷 | CriticalSection/Mutex/Event 同步物件 |
| TSR 常駐 (INT 27h/31h) | Service/DLL Injection/全域鉤子 |
最小可執行骨架
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE \MASM32\INCLUDE\WINDOWS.INC
INCLUDE \MASM32\INCLUDE\KERNEL32.INC
INCLUDELIB \MASM32\LIB\KERNEL32.LIB
.CODE
START:
INVOKE ExitProcess, 0
END START
編譯連結後僅 1.5 KB,驗證工具鏈、PE 結構、入口點、API 呼叫完整運作。
- 上一篇文章: Win32 組合語言教學:MessageBox 訊息框與 INVOKE 參數型別檢查
- 下一篇文章: Win32 組合語言進階:超類別化 實作唯讀十六進位編輯框與 Tab 切換
Copyright ©
程式碼之家 All Rights Reserved