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

Win32 組合語言圖形程式設計入門:位圖載入與雙緩衝繪圖

     編輯:組合語言

前言

位圖(Bitmap, .bmp)是 Windows 原生支援的影像格式。在視窗程式中顯示位圖,核心流程是:載入資源 → 取得裝置內容 (DC) → 建立相容記憶體 DC → 選入位圖 → BitBlt/StretchBlt 複製到螢幕 DC → 釋放資源。本文詳細說明每個步驟對應的 API、參數與完整範例。

1. 將位圖加入資源檔

資源腳本 (.rc) 中定義位圖有兩種方式:

; 方式一:整數 ID
#define IDB_MYBITMAP 100
IDB_MYBITMAP BITMAP "c:\project\example.bmp"

; 方式二:字串名稱
MyBitMap BITMAP "c:\project\example.bmp"

編譯後,位圖嵌入 EXE 資源區。程式中以 LoadBitmap 載入:

LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR
; 返回位圖控制代碼 (HBITMAP)
  • 整數 ID 版:invoke LoadBitmap, hInstance, IDB_MYBITMAP(或直接傳數值 100)。
  • 字串名稱版:invoke LoadBitmap, hInstance, addr BitmapName(BitmapName db "MyBitMap",0)。

2. 取得裝置內容 (DC)

  • WM_PAINT 回應中:BeginPaint(hwnd, &ps) 取得客戶區 DC,繪圖結束需 EndPaint。
  • 其他時機:GetDC(hwnd) 取得 DC,用畢需 ReleaseDC。

3. 雙緩衝繪圖:建立記憶體 DC 並選入位圖

CreateCompatibleDC proto hdc:HDC
; 返回記憶體 DC 控制代碼,作為「隱藏畫布」

SelectObject proto hdc:HDC, hGdiObject:DWORD
; 將位圖選入記憶體 DC,返回先前被替換的 GDI 物件控制代碼(繪圖結束需選回)

流程:

  1. hdc = BeginPaint(...)
  2. hMemDC = CreateCompatibleDC(hdc)
  3. hOldBmp = SelectObject(hMemDC, hBitmap)

4. 將位圖複製到螢幕 DC:BitBlt vs StretchBlt

BitBlt proto hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, nWidth:DWORD, nHeight:DWORD, \
             hdcSrc:DWORD, nxSrc:DWORD, nySrc:DWORD, dwROP:DWORD

StretchBlt proto hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, nWidth:DWORD, nHeight:DWORD, \
                hdcSrc:DWORD, nxSrc:DWORD, nySrc:DWORD, nWidthSrc:DWORD, nHeightSrc:DWORD, dwROP:DWORD
  • BitBlt:像素對像素直接複製,速度最快。適用於位圖尺寸等於顯示區域。
  • StretchBlt:可拉伸/壓縮來源影像以符合目的區域尺寸。適用於位圖與視窗大小不一致時。
  • dwROP:光柵操作碼,常用 SRCCOPY(直接覆蓋)。

5. 資源清理

SelectObject(hMemDC, hOldBmp)   ; 還原記憶體 DC 原狀
DeleteDC(hMemDC)                ; 刪除記憶體 DC
EndPaint(hwnd, &ps)             ; 釋放螢幕 DC
DeleteObject(hBitmap)           ; 程式結束時釋放位圖物件

完整範例:視窗客戶區顯示位圖

.386
.model flat,stdcall
option casemap:none
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\gdi32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\gdi32.lib

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
IDB_MAIN equ 1

.data
ClassName db "SimpleWin32ASMBitmapClass",0
AppName   db "Win32ASM Simple Bitmap Example",0

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hBitmap dd ?

.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 hInstance
    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, SW_SHOWNORMAL
    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
    LOCAL ps:PAINTSTRUCT
    LOCAL hdc:HDC
    LOCAL hMemDC:HDC
    LOCAL rect:RECT

    .if uMsg == WM_CREATE
        invoke LoadBitmap, hInstance, IDB_MAIN
        mov hBitmap, eax

    .elseif uMsg == WM_PAINT
        invoke BeginPaint, hWnd, addr ps
        mov hdc, eax
        invoke CreateCompatibleDC, hdc
        mov hMemDC, eax
        invoke SelectObject, hMemDC, hBitmap
        invoke GetClientRect, hWnd, addr rect
        invoke BitBlt, hdc, 0, 0, rect.right, rect.bottom, hMemDC, 0, 0, SRCCOPY
        invoke DeleteDC, hMemDC
        invoke EndPaint, hWnd, addr ps

    .elseif uMsg == WM_DESTROY
        invoke DeleteObject, hBitmap
        invoke PostQuitMessage, NULL

    .ELSE
        invoke DefWindowProc, hWnd, uMsg, wParam, lParam
        ret
    .ENDIF
    xor eax, eax
    ret
WndProc endp
end start

; 資源定義 (在 .rc 檔中)
#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bmp"

關鍵點解析

  • WM_CREATE:視窗建立時載入位圖資源,儲存 hBitmap 供後續繪圖使用。
  • WM_PAINT:每次視窗需重繪時執行雙緩衝流程。GetClientRect 取得客戶區尺寸,BitBlt 將記憶體 DC 內容完整複製到螢幕 DC。
  • WM_DESTROY:釋放位圖物件,發送退出訊息結束訊息迴路。
  • 雙緩衝優勢:避免直接在螢幕 DC 繪圖造成閃爍,尤其在頻繁重繪(動畫、遊戲)時效果顯著。

延伸應用

  • 使用 StretchBlt 實作位圖縮放、平鋪、鏡像。
  • 結合 TransparentBlt(需 msimg32.lib)實現透明色繪製。
  • 離屏渲染:在記憶體 DC 上疊加多張位圖、文字、幾何圖形,最後一次 BitBlt 呈現。
  • 直接操作 DIB (Device-Independent Bitmap) 像素陣列,實現像素級特效、影像處理。

總結

Win32 位圖顯示的核心是 DC 機制與 BitBlt/StretchBlt。掌握資源載入、雙緩衝流程、資源釋放時機,即可在組合語言中實作高效能的 2D 圖形輸出。下一步可探索 GDI+、Direct2D 或 Direct3D 以獲得硬體加速與更豐富的繪圖功能。

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