news 2026/8/28 1:27:57

汇编语言全接触-25.位图初步

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
汇编语言全接触-25.位图初步

在这一课,我们将学习怎样在程序中使用位图。 更准确地说,我们要学习的是怎样在一个窗口的客户区中显示位图。

理论

位图就是存贮于电脑中的图片。位图文件有相当多的格式(译者:如.BMP.JPG.GIF.PIC 等)但Windows仅支持 Windows Bitmap Graphics 格式,即BMP文件。 本课所指的位图也是BMP文件。 使用位图最简单的方法就是把它定义在资源文件(.rc)中。 定义的方法有两种。第一种方法是把它定义为整数宏,具体如下:

#define IDB_MYBITMAP 100

IDB_MYBITMAP BITMAP "c:\project\example.bmp"

第一行我们定义了一个值为100的整数宏。 第二行我们把这个整数宏指向所要定义的位图, 这样,编译器就能知道位图所在的路径。

另一种方法是给它起一个名字,也就是把它定义为字符串,具体如下:

MyBitMap BITMAP "c:\project\example.bmp"

两种方法效果是一样的。选择哪一种方法,视乎在程序中你喜欢用整数宏还是用字符串来指向位图。

现在我们已经把位图定义在资源文件中,下一步就是把它显示在窗口的客户区上。

在程序中,我们使用API函数 LoadBitmap 取得位图句柄。 下面是 LoadBitmap 函数的 完型:

LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR

该函数返回一个位图句柄。函数有两个参数,其中 hInstance 是程序句柄。 lpBitmapName 是位图名字的指针(适用于第二种定义方法)。如果你使用了第一种 定义方法,你可以填入指向位图的值或整数宏 (对应上例这个值就是100,整数宏是IDB_MYBITMAP)。下面是简单的例子:

第一种方法:

.386

.model flat, stdcall

................

.const

IDB_MYBITMAP equ 100

...............

.data?

hInstance dd ?

..............

.code

.............

invoke GetModuleHandle,NULL

mov hInstance,eax

............

invoke LoadBitmap,hInstance,IDB_MYBITMAP

...........

第二种方法:

.386

.model flat, stdcall

................

.data

BitmapName db "MyBitMap",0

...............

.data?

hInstance dd ?

..............

.code

.............

invoke GetModuleHandle,NULL

mov hInstance,eax

............

invoke LoadBitmap,hInstance,addr BitmapName

...........

获得一个设备文本(DC)句柄。你可以在响应WM_PAINT消息时通过API函数BeginPaint获得。 如果在其它消息中则可以用API函数GetDC获得。

创建这个DC的内存映像。这样做的目的是建立一张“隐藏的画纸”,把位图 “画”在上面,作缓冲之用。完成这项工作后,我们就通过一个函数把“画纸”上的位图复制 到真正的DC中。这就是在屏幕上快速显示图象的双缓冲技术。(译者:可以减少图象抖动) 这张“画纸”用API函数 CreateCompatibleDC 建立,下面是它的完型:

CreateCompatibleDC proto hdc:HDC

如果函数执行成功,将返回DC内存映像也即“画纸”的句柄。

现在我们已经有了“画纸”,可以把位图画在上面了。这可以通过API函数 SelectObject 完成, 其中第一个参数是“画纸”的句柄,第二个参数则是位图的句柄,下面是函数的完型:

SelectObject proto hdc:HDC, hGdiObject:DWORD

现在位图已经画在“画纸”上了。下一步我们要把位图复制到真正的DC中。 有很多API函数都能完成这项工作,例如 BitBlt 和 StretchBlt。 函数 BitBlt 仅仅将一个DC的内容简单地复制到另一个DC中,而函数 StretchBlt 则能够自动调整源DC复制内容的大小已适应目的DC的输出区域大小,因此前者比后者速度更快。 在这里我们只使用函数 BitBlt ,下面是它的完型:

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

hdcDest 目的DC的句柄。

nxDest, nyDest 目的DC输出区域的左上角坐标。

nWidth, nHeight 目的DC输出区域的长和宽。

hdcSrc 源DC的句柄。

nxSrc, nySrc 源DC中所要复制区域的左上角坐标。

dwROP 屏面运算码(ROP)。该参数用以确定复制内容的颜色与输出区域原来的颜色按哪种运算 方式处理。通常,只需要简单地用复制内容把输出区域覆盖掉。

一切办妥后,就用API函数 DeleteObject 释放位图对象,也就是把位图“抹掉”。

大功告成! 现在再来回顾一下整个过程:首先,你需要把位图定义在资源文件中。 然后,你需要在程序中载入位图资源,并取得位图句柄。随后,你需要获得位图输出区域的DC,以及创建这个DC的内存映像,并把位图放进这个DC内存映像中。最后把位图从DC内存映像复制到真正的DC中。

例子:

.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

;---------------------------------------------------------------------

; 资源定义

;---------------------------------------------------------------------

#define IDB_MAIN 1

IDB_MAIN BITMAP "tweety78.bmp"

分析:

#define IDB_MAIN 1

IDB_MAIN BITMAP "tweety78.bmp"

定义整数宏IDB_MAIN的值为1,然后把它指向一个与资源文件处于相同目录文件名为“tweety.bmp"的位图。

.if uMsg==WM_CREATE

invoke LoadBitmap,hInstance,IDB_MAIN

mov hBitmap,eax

在处理 WM_CREATE 消息时, 我们通过API函数 LoadBitmap 载入位图资源,并通过函数返回值取得位图句柄。

然后,我们就可以把位图画在窗口客户区上。

.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

在本例中,我们选用在响应WM_PAINT消息时画出位图。首先我们通过API函数l BeginPaint 获得窗口客户区的DC句柄。 接着我们通过API函数 CreateCompatibleDC 创建该DC 的内存映像,并通过API函数 SelectObject 把位图放进内存映像中。下一步,我们通过API函数 GetClientRect 取得窗口客户区的大小。最后,我们通过API函数 BitBlt 把位图从DC内存映像复制到真正的客户区DC中。 完成显示工作后,我们通过API函数 DeleteDC 释放DC内存映像,并用API函数 EndPaint 释放客户区DC, 结束画图工作。

.elseif uMsg==WM_DESTROY

invoke DeleteObject,hBitmap

invoke PostQuitMessage,NULL

当我们不再需要位图时,通过API函数 DeleteObject 把它释放。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/28 1:03:10

面试常考:如何原地重排数组?这个思路绝了

解题思路 这道题我们用两个指针分别追踪奇数位和偶数位,每次检查最后一个元素是奇数还是偶数,然后把它交换到对应的位置上。 比如最后一个元素是奇数,就把它换到下一个需要填充的奇数位(1, 3, 5…),换过来的元素又成为新的"最后一个元素",继续这个过程。 这样做的优势…

作者头像 李华
网站建设 2026/8/27 18:00:58

Wi-Fi CERTIFIED Multimedia™ (WMM®) 技术概述

1.0 概述 本文档定义了 WMM 的规范,WMM 是基于 IEEE 802.11e 标准补充 [2] 的 802.11 QoS 实现方案。最初提出 WMM 是为了防止因多个不兼容的 802.11e 预标准子集出现而导致的碎片化问题;部署 WMM 将为 802.11 语音、流媒体等服务提供可用的 QoS 功能。 1.1 参考文献 [1] …

作者头像 李华
网站建设 2026/8/27 20:00:15

Astrofy:快速构建现代化个人作品集的免费开源模板

Astrofy:快速构建现代化个人作品集的免费开源模板 【免费下载链接】astrofy Astrofy is a free and open-source template for your Personal Portfolio Website built with Astro and TailwindCSS. Create in minutes a website with Blog, CV, Project Section, S…

作者头像 李华
网站建设 2026/8/26 22:50:23

Opus 音频编解码器深度技术报告:架构原理、传输机制与演进分析

Opus 音频编解码器深度技术报告:架构原理、传输机制与演进分析 1. 引言:音频编码的统一范式 在数字音频处理的历史长河中,音频编码技术长期以来被划分为两个截然不同的阵营:语音编码与通用音频编码。这种二元分化源于应用场景的…

作者头像 李华
网站建设 2026/8/27 22:15:54

Python实现微信域名深度学习驱动的智能对抗性防御与流量伪装系统

Python实现微信域名深度学习驱动的智能对抗性防御与流量伪装系统功能概述本系统实现了一个基于深度强化学习、生成对抗网络和元学习的智能微信域名对抗防御系统。通过多模态特征学习、对抗性流量生成、智能策略优化和联邦学习框架,构建了一个能够持续学习和适应微信…

作者头像 李华