Windows 提供統一的記憶體管理與檔案 I/O API,取代 DOS 時代的中斷呼叫。本課透過一個完整的文字編輯器範例,示範:全域記憶體配置 (GlobalAlloc/Lock/Free)、檔案開啟/讀寫/關閉 (CreateFile/ReadFile/WriteFile/CloseHandle)、通用對話方塊 (GetOpenFileName/GetSaveFileName)、編輯控件文字操作 (WM_SETTEXT/WM_GETTEXT),以及視窗大小自適應調整。
GlobalAlloc 與 LocalAlloc 行為相同,皆從進程堆配置。GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size) → 傳回控制代碼 (HGLOBAL)GlobalLock(hMem) → 傳回指標 (LPVOID),將記憶體鎖定於實體記憶體GlobalUnlock(hMem) → 解除鎖定GlobalFree(hMem) → 釋放記憶體GMEM_FIXED,直接傳回指標,免 Lock/Unlock,釋放用 GlobalFree。CreateFile 開啟/建立檔案 → 傳回 HANDLESetFilePointer 移動檔案指標 (可選,預設開檔位於開頭)ReadFile / WriteFile 執行資料傳輸,自動處理緩衝CloseHandle 關閉檔案控制代碼| 參數 | 常用值 | 說明 |
|---|---|---|
| dwDesiredAccess | GENERIC_READ / GENERIC_WRITE / 兩者 OR | 存取權限 |
| dwShareMode | FILE_SHARE_READ / FILE_SHARE_WRITE / 0 | 共享模式,0 為獨佔 |
| dwCreationDisposition | CREATE_NEW / CREATE_ALWAYS / OPEN_EXISTING / OPEN_ALWAYS / TRUNCATE_EXISTING | 檔案存在/不存在時的行為 |
| dwFlagsAndAttributes | FILE_ATTRIBUTE_NORMAL / ARCHIVE / HIDDEN / READONLY / SYSTEM | 檔案屬性 |
.const
IDM_OPEN equ 1
IDM_SAVE equ 2
IDM_EXIT equ 3
MAXSIZE equ 260
MEMSIZE equ 65535
EditID equ 1
WndProc proc uses ebx hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
.IF uMsg == WM_CREATE
; 建立編輯控件,尺寸設 0 稍後 WM_SIZE 調整
invoke CreateWindowEx, NULL, ADDR EditClass, NULL, \
WS_VISIBLE or WS_CHILD or ES_LEFT or ES_MULTILINE or \
ES_AUTOHSCROLL or ES_AUTOVSCROLL, \
0, 0, 0, 0, hWnd, EditID, hInstance, NULL
mov hwndEdit, eax
invoke SetFocus, hwndEdit
; 初始化 OPENFILENAME 共用欄位
mov ofn.lStructSize, SIZEOF ofn
push hWnd; pop ofn.hWndOwner
push hInstance; pop ofn.hInstance
mov ofn.lpstrFilter, OFFSET FilterString
mov ofn.lpstrFile, OFFSET buffer
mov ofn.nMaxFile, MAXSIZE
.ELSEIF uMsg == WM_SIZE
; 視窗大小改變時,編輯控件填滿客戶區
mov eax, lParam
mov edx, eax
shr edx, 16 ; edx = 高字 = 高度
and eax, 0FFFFh ; eax = 低字 = 寬度
invoke MoveWindow, hwndEdit, 0, 0, eax, edx, TRUE
.ELSEIF uMsg == WM_DESTROY
invoke PostQuitMessage, NULL
.ELSEIF uMsg == WM_COMMAND
mov eax, wParam
.IF lParam == 0 ; 選單項目 (lParam=0)
.IF ax == IDM_OPEN
mov ofn.Flags, OFN_FILEMUSTEXIST or OFN_PATHMUSTEXIST or \
OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
invoke GetOpenFileName, ADDR ofn
.IF eax == TRUE
invoke CreateFile, ADDR buffer, GENERIC_READ or GENERIC_WRITE, \
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, OPEN_EXISTING, \
FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMSIZE
mov hMemory, eax
invoke GlobalLock, hMemory
mov pMemory, eax
invoke ReadFile, hFile, pMemory, MEMSIZE-1, ADDR SizeReadWrite, NULL
invoke SendMessage, hwndEdit, WM_SETTEXT, NULL, pMemory
invoke CloseHandle, hFile
invoke GlobalUnlock, pMemory
invoke GlobalFree, hMemory
.ENDIF
invoke SetFocus, hwndEdit
.ELSEIF ax == IDM_SAVE
mov ofn.Flags, OFN_LONGNAMES or OFN_EXPLORER or OFN_HIDEREADONLY
invoke GetSaveFileName, ADDR ofn
.IF eax == TRUE
invoke CreateFile, ADDR buffer, GENERIC_READ or GENERIC_WRITE, \
FILE_SHARE_READ or FILE_SHARE_WRITE, NULL, CREATE_NEW, \
FILE_ATTRIBUTE_ARCHIVE, NULL
mov hFile, eax
invoke GlobalAlloc, GMEM_MOVEABLE or GMEM_ZEROINIT, MEMSIZE
mov hMemory, eax
invoke GlobalLock, hMemory
mov pMemory, eax
invoke SendMessage, hwndEdit, WM_GETTEXT, MEMSIZE-1, pMemory
invoke WriteFile, hFile, pMemory, eax, ADDR SizeReadWrite, NULL
invoke CloseHandle, hFile
invoke GlobalUnlock, pMemory
invoke GlobalFree, hMemory
.ENDIF
invoke SetFocus, hwndEdit
.ELSE ; IDM_EXIT
invoke DestroyWindow, hWnd
.ENDIF
.ENDIF
.ELSE
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
.ENDIF
xor eax, eax
ret
WndProc endp
lParam 低字 = 客戶區寬度,高字 = 高度。MoveWindow 同時設定位置與尺寸,TRUE 參數要求重繪。
在 WM_CREATE 一次性設定固定欄位 (hWndOwner、hInstance、lpstrFilter、lpstrFile、nMaxFile),每次呼叫前僅需更新 Flags。
SendMessage(hwndEdit, WM_SETTEXT, 0, pMemory) 將記憶體緩衝區內容一次性設入編輯控件。SendMessage(hwndEdit, WM_GETTEXT, MEMSIZE-1, pMemory) 取得編輯控件文字,回傳實際字元數 (不含結束 NULL),直接作為 WriteFile 的寫入長度。範例採用「配置 → 鎖定 → 讀/寫 → 解鎖 → 釋放」完整流程,確保資源正確釋放。實務上可視情況保留記憶體區塊重複使用,減少配置開銷。
; main.asm
.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
include \masm32\include\comdlg32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\comdlg32.lib
; ... (常數、資料、程式碼如上)
end start
#include "resource.h"
#define IDM_OPEN 1
#define IDM_SAVE 2
#define IDM_EXIT 3
#define EditID 1
FirstMenu MENU
BEGIN
POPUP "&File"
BEGIN
MENUITEM "&Open\tCtrl+O", IDM_OPEN
MENUITEM "&Save\tCtrl+S", IDM_SAVE
MENUITEM SEPARATOR
MENUITEM "E&xit", IDM_EXIT
END
END
ml /c /coff /Cp /nologo main.asm
rc /r /fo main.res resource.rc
link /SUBSYSTEM:WINDOWS /LIBPATH:"\masm32\lib" main.obj main.res /OUT:editor.exe
Win32 記憶體管理與檔案 I/O API 設計一致、功能強大。掌握 GlobalAlloc/Lock/Free、CreateFile/ReadFile/WriteFile/CloseHandle、GetOpenFileName/GetSaveFileName 以及編輯控件訊息操作,即可開發具備完整檔案處理能力的 GUI 應用程式。本範例展示的「對話方塊選檔 → 記憶體緩衝 → 編輯控件顯示/編輯 → 存檔」流程,是無數 Windows 應用程式的核心雛形。