在这一课,我们将学习怎样在程序中使用位图。 更准确地说,我们要学习的是怎样在一个窗口的客户区中显示位图。
例子
理论
位图就是存贮于电脑中的图片。位图文件有相当多的格式(译者:如.BMP.JPG.GIF.PIC 等)但Windows仅 支持 Windows Bitmap Graphics 格式,即BMP文件。 本课所指的位图也是BMP文件。 使用位图最简单的方法就是把它定义在资源文件(.rc)中。 定义的方法有两种。第一种方法是把它定义为整数宏,具体如下:
#define IDB_MYBITMA 100
IDB_MYBITMA ITMA quot;c:\project\example.bm quot;
第一行我们定义了一个值为100的整数宏。 第二行我们把这个整数宏指向所要定义的位图, 这样,编译器就能知道位图所在的路径。
另一种方法是给它起一个名字,也就是把它定义为字符串,具体如下:
MyBitMa ITMAP "c:\project\example.bm quot;
两种方法效果是一样的。 选择哪一种方法,视乎在程序中你喜欢用整数宏还是用字符串来指向位图。
现在我们已经把位图定义在资源文件中,下一步就是把它显示在窗口的客户区上。
在程序中,我们使用API函数 LoadBitmap 取得位图句柄。 下面是 LoadBitmap 函数的 完型:
LoadBitmap proto hI tance:HI TANCE, l itma ame:L TR
该函数返回一个位图句柄。函数有两个参数,其中 hI tance 是程序句柄。 l itma ame 是位图名字的指针(适用于第二种定义方法)。如果你使用了第一种 定义方法,你可以填入指向位图的值或整数宏 (对应上例这个值就是100,整数宏是IDB_MYBITMAP)。下面是简单的例子:
第一种方法:
.386
.model flat, stdcall
................
.co t
IDB_MYBITMA equ 100
...............
.data?
hI tance dd ?
..............
.code
.............
invoke GetModuleHandle,NULL
mov hI tance,eax
............
invoke LoadBitmap,hI tance,IDB_MYBITMAP
...........
第二种方法:
.386
.model flat, stdcall
................
.data
Bitma ame db "MyBitMa quot;,0
...............
.data?
hI tance dd ?
..............
.code
.............
invoke GetModuleHandle,NULL
mov hI tance,eax
............
invoke LoadBitmap,hI tance,addr Bitma ame
...........
获得一个设备文本(DC)句柄。你可以在响应WM_PAINT消息时通过API函数Begi aint获得。 如果在其它消息中则可以用API函数GetDC获得。
创建这个DC的内存映像。这样做的目的是建立一张“隐藏的画纸”,把位图 “画”在上面,作缓冲之用。完成这项工作后,我们就通过一个函数把“画纸”上的位图复制 到真正的DC中。这就是在屏幕上快速显示图象的双缓冲技术。(译者:可以减少图象抖动) 这张“画纸”用API函数 CreateCompatibleDC 建立,下面是它的完型:
CreateCompatibleDC roto hdc:HDC
如果函数执行成功,将返回DC内存映像也即“画纸”的句柄。
现在我们已经有了“画纸”,可以把位图画在上面了。这可以通过API函数 SelectObject 完成, 其中第一个参数是“画纸”的句柄,第二个参数则是位图的句柄,下面是函数的完型:
SelectObject proto hdc:HDC, hGdiObject:DWORD
现在位图已经画在“画纸”上了。下一步我们要把位图复制到真正的DC中。 有很多API函数都能完成这项工作,例如 BitBlt 和 StretchBlt。 函数 BitBlt 仅仅将一个DC的内容简单地复制到另一个DC中,而函数 StretchBlt 则能够自动调整源DC复制内容的大小已适应目的DC的输出区域大小,因此前者比后者速度更快。 在这里我们只使用函数 BitBlt ,下面是它的完型:
BitBlt roto 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_MAI equ 1
.data
Cla ame db " impleWin32ASMBitmapCla quot;,0
A ame db "Win32ASM Simple Bitmap Example",0
.data?
hI tance HI TANCE ?
CommandLine L TR ?
hBitmap dd ?
.code
start:
invoke GetModuleHandle, NULL
mov hI tance,eax
invoke GetCommandLine
mov CommandLine,eax
invoke WinMain, hI tance,NULL,CommandLine, SW_SHOWDEFAULT
invoke ExitProce ,eax
WinMain proc hI t:HI TANCE,hPrevI t:HI TANCE,CmdLine:L TR,CmdShow:DWORD
LOCAL wc:WNDCLA EX
LOCAL msg:MSG
LOCAL hwnd:HWND
mov wc.c ize,SIZEOF WNDCLA EX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra,NULL
mov wc.cbWndExtra,NULL
push hI tance
po wc.hI tance
mov wc.hbrBackground,COLOR_WINDOW+1
mov wc.l zMenuName,NULL
mov wc.l zCla ame,OFFSET Cla ame
invoke LoadIcon,NULL,IDI_A LICATION
mov wc.hIcon,eax
mov wc.hIco m,eax
invoke LoadCursor,NULL,IDC_ARROW
mov wc.hCursor,eax
invoke RegisterCla Ex, addr wc
INVOKE CreateWindowEx,NULL,ADDR Cla ame,ADDR A ame,\
WS_OVERLA EDWINDOW,CW_USEDEFAULT,\
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
hI t,NULL
mov hwnd,eax
invoke ShowWindow, hwnd,SW_SHOWNORMAL
invoke UpdateWindow, hwnd
.while TRUE
invoke GetMe age, ADDR msg,NULL,0,0
.break .if (!eax)
invoke Tra lateMe age, ADDR msg
invoke Di atchMe age, ADDR msg
.endw
mov eax,msg.wParam
ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
LOCAL :PAINTSTRUCT
LOCAL hdc:HDC
LOCAL hMemDC:HDC
LOCAL rect:RECT
.if uMsg==WM_CREATE
invoke LoadBitmap,hI tance,IDB_MAIN
mov hBitmap,eax
.elseif uMsg==WM_PAINT
invoke Begi aint,hWnd,addr
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
.elseif uMsg==WM_DESTROY
invoke DeleteObject,hBitmap
invoke PostQuitMe age,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.bm quot;
分析:
#define IDB_MAIN 1
IDB_MAIN BITMAP "tweety78.bm quot;
定义整数宏IDB_MAIN的值为1,然后把它指向一个与资源文件处于相同目录文件名为“tweety.bm quot;的位图。
.if uMsg==WM_CREATE
invoke LoadBitmap,hI tance,IDB_MAIN
mov hBitmap,eax
在处理 WM_CREATE 消息时, 我们通过API函数 LoadBitmap 载入位图资源,并通过函数 返回值取得位图句柄。
然后,我们就可以把位图画在窗口客户区上。
.elseif uMsg==WM_PAINT
invoke Begi aint,hWnd,addr
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
在本例中,我们选用在响应WM_PAINT消息时画出位图。首先我们通过API函数l Begi aint 获得窗口客户区的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 PostQuitMe age,NULL
当我们不再需要位图时,通过API函数 DeleteObject 把它释放。


