教學目標
以最精簡的 Win32 程式呼叫 MessageBox 顯示對話框,並深入解析 INVOKE 高層呼叫指令的參數型別檢查機制、ADDR vs OFFSET 差異、動態連結庫匯入庫鏈接流程。
最小程式碼
.386
.MODEL FLAT, STDCALL
OPTION CASEMAP:NONE
INCLUDE \MASM32\INCLUDE\WINDOWS.INC
INCLUDE \MASM32\INCLUDE\KERNEL32.INC
INCLUDELIB \MASM32\LIB\KERNEL32.LIB
INCLUDE \MASM32\INCLUDE\USER32.INC
INCLUDELIB \MASM32\LIB\USER32.LIB
.DATA
MsgBoxCaption DB "Iczelion Tutorial No.2",0
MsgBoxText DB "Win32 Assembly is Great!",0
.CODE
START:
INVOKE MessageBox, NULL, ADDR MsgBoxText, ADDR MsgBoxCaption, MB_OK
INVOKE ExitProcess, NULL
END START
MessageBox 原型與參數
MessageBox PROTO hWnd:DWORD, lpText:DWORD, lpCaption:DWORD, uType:DWORD
hWnd:父視窗控制代碼,NULL 表無擁有者,對話框置中於螢幕
lpText:訊息字串指標 (ANSI 版 MessageBoxA)
lpCaption:標題列字串指標
uType:按鈕/圖示/預設按鈕/模態類型組合,MB_OK = 僅確定鍵 + 資訊圖示
INVOKE 參數型別檢查機制
INVOKE 會依據 PROTO 宣告的參數型別,於組譯期檢查:
- 參數個數是否符合
- 每個參數大小是否匹配 (DWORD=4 位元組,WORD=2,BYTE=1,QWORD=8)
- 立即數是否超出目標型別範圍
對比 CALL:CALL MessageBox 完全無檢查,若堆疊參數錯誤只會在執行期崩潰;INVOKE 編譯期即報錯,大幅降低除錯成本。
ADDR vs OFFSET 關鍵差異
| 運算子 | 適用範圍 | 機制 | 限制 |
OFFSET | 全域/靜態變數 | 組譯期解析位址,直接嵌入機器碼 | 無法處理區域變數 (堆疊相對位址) |
ADDR | 全域/靜態/區域變數 | 組譯期檢查:全域同 OFFSET;區域產生 LEA EAX, var / PUSH EAX 序列 | 無法處理前向參考 (變數定義在 INVOKE 之後) |
前向參考範例
; 錯誤:ADDR 無法解析前向標號
INVOKE MessageBox, NULL, ADDR MsgBoxText, ADDR MsgBoxCaption, MB_OK
...
MsgBoxCaption DB "...",0
MsgBoxText DB "...",0
; 正確:改用 OFFSET
INVOKE MessageBox, NULL, OFFSET MsgBoxText, OFFSET MsgBoxCaption, MB_OK
區域變數範例
WndProc PROC hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL szBuf[256]:BYTE
INVOKE lstrcpy, ADDR szBuf, ADDR SrcText ; 正確:ADDR 產生 LEA 序列
; INVOKE lstrcpy, OFFSET szBuf, ... ; 錯誤:OFFSET 無法取得堆疊位址
RET
WndProc ENDP
動態連結庫匯入庫鏈接流程
INCLUDE USER32.INC:引入 MessageBox PROTO ... 等原型宣告
INCLUDELIB USER32.LIB:在 .obj 嵌入連結器指令「鏈接 USER32.LIB」
ML /c /coff /Cp:產生 .obj (COFF 格式)
LINK /SUBSYSTEM:WINDOWS /LIBPATH:C:\MASM32\LIB file.obj:
- 讀取
USER32.LIB 匯入庫,解析 MessageBox 等符號
- 在可執行檔
.idata 區建立匯入表:DLL 名稱 + 函數名/序數
- 修正
CALL [IAT_MessageBox] 等指令位址
- 執行時:Windows 載入器依匯入表載入
USER32.DLL,填入 IAT 實際位址
ANSI vs Unicode 版本
MessageBoxA (ANSI):字串為單位元組字元,windows.inc 以 MessageBox EQU 為預設
MessageBoxW (Unicode):字串為雙位元組寬字元,需定義 UNICODE 宏或直接呼叫 MessageBoxW
- 現代建議:統一使用 Unicode 版本,字串前綴
L"..." 或 _TEXT("...")
建置與驗證
ML /c /coff /Cp MSGBOX.ASM
LINK /SUBSYSTEM:WINDOWS /LIBPATH:C:\MASM32\LIB MSGBOX.OBJ
; 產生 MSGBOX.exe (約 1.5 KB),執行即見對話框
- 上一篇文章: Win32 螢幕保護程式開發完整指南:SCRNSAVE.LIB 架構與實作範本
- 下一篇文章: Win32 組合語言基礎:FLAT 模式、STDCALL 慣例、段偽指令與程式框架
Copyright ©
程式碼之家 All Rights Reserved