位图就是存贮于电脑中的图片。位图文件有相当多的格式(译者:如.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 ...........
reateCompatibleDC proto hdc:HDC
如果函数执行成功,将返回DC内存映像也即“画纸”的句柄。
electObject proto hdc:HDC, hGdiObject:DWORD
itBlt 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)。该参数用以确定复制内容的颜色与输出区域原来的颜色按哪种运算
方式处理。通常,只需要简单地用复制内容把输出区域覆盖掉。
.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 把它释放。