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

Win32 組語教學:記憶體管理與檔案 I/O 完整實作

     編輯:組合語言

前言

Windows 提供統一的記憶體管理與檔案 I/O API,取代 DOS 時代的中斷呼叫。本課透過一個完整的文字編輯器範例,示範:全域記憶體配置 (GlobalAlloc/Lock/Free)、檔案開啟/讀寫/關閉 (CreateFile/ReadFile/WriteFile/CloseHandle)、通用對話方塊 (GetOpenFileName/GetSaveFileName)、編輯控件文字操作 (WM_SETTEXT/WM_GETTEXT),以及視窗大小自適應調整。

Win32 記憶體管理模型

  • 平坦模式:每進程 4GB 虛擬位址空間,段暫存器同基址,無 near/far 之分。
  • Global/Local 統一:GlobalAlloc 與 LocalAlloc 行為相同,皆從進程堆配置。
  • 標準流程:
  1. GlobalAlloc(GMEM_MOVEABLE | GMEM_ZEROINIT, size) → 傳回控制代碼 (HGLOBAL)
  2. GlobalLock(hMem) → 傳回指標 (LPVOID),將記憶體鎖定於實體記憶體
  3. 透過指標讀寫資料
  4. GlobalUnlock(hMem) → 解除鎖定
  5. GlobalFree(hMem) → 釋放記憶體
  • GMEM_FIXED 簡化法:配置時指定 GMEM_FIXED,直接傳回指標,免 Lock/Unlock,釋放用 GlobalFree。

檔案 I/O 基本流程

  1. CreateFile 開啟/建立檔案 → 傳回 HANDLE
  2. SetFilePointer 移動檔案指標 (可選,預設開檔位於開頭)
  3. ReadFile / WriteFile 執行資料傳輸,自動處理緩衝
  4. CloseHandle 關閉檔案控制代碼

CreateFile 關鍵參數

參數常用值說明
dwDesiredAccessGENERIC_READ / GENERIC_WRITE / 兩者 OR存取權限
dwShareModeFILE_SHARE_READ / FILE_SHARE_WRITE / 0共享模式,0 為獨佔
dwCreationDispositionCREATE_NEW / CREATE_ALWAYS / OPEN_EXISTING / OPEN_ALWAYS / TRUNCATE_EXISTING檔案存在/不存在時的行為
dwFlagsAndAttributesFILE_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

關鍵技巧解析

1. WM_SIZE 自適應編輯控件

lParam 低字 = 客戶區寬度,高字 = 高度。MoveWindow 同時設定位置與尺寸,TRUE 參數要求重繪。

2. 通用對話方塊 OPENFILENAME 初始化

在 WM_CREATE 一次性設定固定欄位 (hWndOwner、hInstance、lpstrFilter、lpstrFile、nMaxFile),每次呼叫前僅需更新 Flags。

3. 編輯控件文字傳輸:WM_SETTEXT / WM_GETTEXT

  • 讀檔後:SendMessage(hwndEdit, WM_SETTEXT, 0, pMemory) 將記憶體緩衝區內容一次性設入編輯控件。
  • 存檔前:SendMessage(hwndEdit, WM_GETTEXT, MEMSIZE-1, pMemory) 取得編輯控件文字,回傳實際字元數 (不含結束 NULL),直接作為 WriteFile 的寫入長度。

4. 記憶體配置與檔案 I/O 同步

範例採用「配置 → 鎖定 → 讀/寫 → 解鎖 → 釋放」完整流程,確保資源正確釋放。實務上可視情況保留記憶體區塊重複使用,減少配置開銷。

完整專案結構

; 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

資源腳本 (resource.rc)


#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 應用程式的核心雛形。

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