?? lion-tutorial25.htm
字號:
<html>
<head>
<link rel="stylesheet" href="../../asm.css">
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<title>Iczelion's win32 asm tutorial</title>
</head>
<body bgcolor="#FFFFFF" background="../../images/back01.jpg">
<p align="center">Tutorial 25: Simple Bitmap</p>
<hr size="1">
<strong> </strong> In this tutorial, we will learn how to use bitmap in our program.
To be exact, we will learn how to display a bitmap in the client area of our window.
Download <a href="files/tut25.zip">the example</a>.
<h3> Theory</h3>
Bitmaps can be thought of as pictures stored in computer. There are many picture
formats used with computers but Windows only natively supports Windows Bitmap
Graphics files (.bmp). The bitmaps I'll refer to in this tutorial are Windows
bitmap graphics files. The easiest way to use a bitmap is to use it as a resource.
There are two ways to do that. You can include the bitmap in the resource definition
file (.rc) as follows: <br>
<blockquote>#define IDB_MYBITMAP 100 <br>
IDB_MYBITMAP <b>BITMAP</b> "c:\project\example.bmp"</blockquote>
This method uses a constant to represent the bitmap. The first line just creates
a constant named IDB_MYBITMAP which has the value of 100. We will use this label
to refer to the bitmap in the program. The next line declares a bitmap resource.
It tells the resource compiler where to find the actual bmp file. <br>
The other method uses a name to represent the bitmap as follows:
<blockquote>MyBitMap <b>BITMAP</b> "c:\project\example.bmp"</blockquote>
This method requires that you refer to the bitmap in your program by the string
"MyBitMap" instead of a value. <br>
Either method works fine as long as you know which method you're using. <br>
Now that we put the bitmap in the resource file, we can go on with the steps in
displaying it in the client area of our window.
<ol>
<li> call LoadBitmap to get the bitmap handle. LoadBitmap has the following
definition:</li>
</ol>
<ol>
<ol>
<b>LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR</b>
</ol>
<p><br>
This function returns a bitmap handle. hInstance is the instance handle of
our program. lpBitmapName is a pointer to the string that is the name of the
bitmap (incase you use the second method to refer to the bitmap). If you use
a constant to refer to the bitmap (like IDB_MYBITMAP), you can put its value
here. (In the example above it would be 100). A short example is in order:
<ol>
<br>
First Method:
<p>.386 <br>
.model flat, stdcall <br>
................ <br>
.const <br>
IDB_MYBITMAP equ 100 <br>
............... <br>
.data? <br>
hInstance dd ? <br>
.............. <br>
.code <br>
............. <br>
invoke GetModuleHandle,NULL <br>
mov hInstance,eax <br>
............ <br>
invoke LoadBitmap,hInstance,IDB_MYBITMAP <br>
...........
<p>Second Method:
<p>.386 <br>
.model flat, stdcall <br>
................ <br>
.data <br>
BitmapName db "MyBitMap",0 <br>
............... <br>
.data? <br>
hInstance dd ? <br>
.............. <br>
.code <br>
............. <br>
invoke GetModuleHandle,NULL <br>
mov hInstance,eax <br>
............ <br>
invoke LoadBitmap,hInstance,addr BitmapName <br>
...........
</ol>
<li> Obtain a handle to device context (DC). You can obtain this handle by calling
BeginPaint in response to WM_PAINT message or by calling GetDC anywhere.</li>
<li> Create a memory device context which has the same attribute as the device
context we just obtained. The idea here is to create a kind of "hidden" drawing
surface which we can draw the bitmap on. When we are finished with the operation,
we just copy the content of the hidden drawing surface to the actual device
context in one function call. It's an example of double-buffer technique used
for fast display of pictures on the screen. You can create this "hidden" drawing
surface by calling CreateCompatibleDC.</li>
</ol>
<ol>
<ol>
CreateCompatibleDC proto hdc:HDC
</ol>
<p><br>
If this function succeeds, it returns the handle of the memory device context
in eax. hdc is the handle to the device context that you want the memory DC
to be compatible with.
<li> Now that you got a hidden drawing surface, you can draw on it by selecting
the bitmap into it. This is done by calling SelectObject with the handle to
the memory DC as the first parameter and the bitmap handle as the second parameter.
SelectObject has the following definition:</li>
</ol>
<ol>
<ol>
SelectObject proto hdc:HDC, hGdiObject:DWORD
</ol>
<li> The bitmap is drawn on the memory device context now. All we need to do
here is to copy it to the actual display device, namely the true device context.
There are several functions that can perform this operation such as BitBlt
and StretchBlt. BitBlt just copies the content of one DC to another so it's
fast while StretchBlt can stretch or compress the bitmap to fit the output
area. We will use BitBlt here for simplicity. BitBlt has the following definition:</li>
</ol>
<ol>
<ol>
BitBlt proto hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, nWidth:DWORD,
nHeight:DWORD, hdcSrc:DWORD, nxSrc:DWORD, nySrc:DWORD, dwROP:DWORD <br>
</ol>
<b>hdcDest</b> is the handle of the device context that serves as the destination
of bitmap transfer operation <br>
<b>nxDest, nyDest </b>are the coordinate of the upper left corner of the output
area <br>
<b>nWidth, nHeight </b>are the width and height of the output area <br>
<b>hdcSrc </b>is the handle of the device context that serves as the source
of bitmap transfer operation <br>
<b>nxSrc, nySrc </b>are the coordinate of the upper left corner of the source
rectangle. <br>
<b>dwROP </b>is the raster-operation code (hence the acronym ROP) that governs
how to combine the color data of the bitmap to the existing color data on the
output area to achieve the final result. Most of the time, you only want to
overwrite the existing color data with the new one.
<li> When you're done with the bitmap, delete it with DeleteObject API call.</li>
</ol>
That's it! To recapitulate, you need to put the bitmap into the resource scipt.
Then load it from the resource with LoadBitmap. You'll get the bitmap handle.
Next you obtain the handle to the device context of the area you want to paint
the bitmap on. Then you create a memory device context that is compatible with
the device context you just obtained. Select the bitmap into the memory DC then
copy the content of the memory DC to the real DC.
<h3> Example Code:</h3>
.386 <br>
.model flat,stdcall <br>
option casemap:none <br>
include \masm32\include\windows.inc <br>
include \masm32\include\user32.inc <br>
include \masm32\include\kernel32.inc <br>
include \masm32\include\gdi32.inc <br>
includelib \masm32\lib\user32.lib <br>
includelib \masm32\lib\kernel32.lib <br>
includelib \masm32\lib\gdi32.lib
<p> WinMain proto :DWORD,:DWORD,:DWORD,:DWORD <br>
<b> IDB_MAIN equ 1 </b>
<p> .data <br>
ClassName db "SimpleWin32ASMBitmapClass",0 <br>
AppName db "Win32ASM Simple Bitmap Example",0
<p> .data? <br>
hInstance HINSTANCE ? <br>
CommandLine LPSTR ? <br>
hBitmap dd ?
<p> .code <br>
start: <br>
invoke GetModuleHandle, NULL <br>
mov hInstance,eax <br>
invoke GetCommandLine <br>
mov CommandLine,eax <br>
invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT <br>
invoke ExitProcess,eax
<p> WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
<br>
LOCAL wc:WNDCLASSEX <br>
LOCAL msg:MSG <br>
LOCAL hwnd:HWND <br>
mov wc.cbSize,SIZEOF WNDCLASSEX <br>
mov wc.style, CS_HREDRAW or CS_VREDRAW <br>
mov wc.lpfnWndProc, OFFSET WndProc <br>
mov wc.cbClsExtra,NULL <br>
mov wc.cbWndExtra,NULL <br>
push hInstance <br>
pop wc.hInstance <br>
mov wc.hbrBackground,COLOR_WINDOW+1 <br>
mov wc.lpszMenuName,NULL <br>
mov wc.lpszClassName,OFFSET ClassName <br>
invoke LoadIcon,NULL,IDI_APPLICATION <br>
mov wc.hIcon,eax <br>
mov wc.hIconSm,eax <br>
invoke LoadCursor,NULL,IDC_ARROW <br>
mov wc.hCursor,eax <br>
invoke RegisterClassEx, addr wc <br>
INVOKE CreateWindowEx,NULL,ADDR ClassName,ADDR AppName,\ <br>
WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,\
<br>
CW_USEDEFAULT,CW_USEDEFAULT,CW_USEDEFAULT,NULL,NULL,\
<br>
hInst,NULL
<br>
mov hwnd,eax <br>
invoke ShowWindow, hwnd,SW_SHOWNORMAL <br>
invoke UpdateWindow, hwnd <br>
.while TRUE <br>
invoke GetMessage, ADDR msg,NULL,0,0 <br>
.break .if (!eax) <br>
invoke TranslateMessage, ADDR msg <br>
invoke DispatchMessage, ADDR msg <br>
.endw <br>
mov eax,msg.wParam <br>
ret <br>
WinMain endp
<p> WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM <br>
LOCAL ps:PAINTSTRUCT <br>
LOCAL hdc:HDC <br>
LOCAL hMemDC:HDC <br>
LOCAL rect:RECT <br>
.if uMsg==WM_CREATE <br>
<b> invoke LoadBitmap,hInstance,IDB_MAIN </b>
<br>
<b> mov hBitmap,eax </b> <br>
.elseif uMsg==WM_PAINT <br>
<b> invoke BeginPaint,hWnd,addr ps </b>
<br>
<b> mov hdc,eax </b>
<br>
<b> invoke CreateCompatibleDC,hdc </b>
<br>
<b> mov hMemDC,eax </b>
<br>
<b> invoke SelectObject,hMemDC,hBitmap </b>
<br>
<b> invoke GetClientRect,hWnd,addr rect </b>
<br>
<b> invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY </b>
<br>
<b> invoke DeleteDC,hMemDC </b> <br>
<b> invoke EndPaint,hWnd,addr ps </b>
<br>
.elseif uMsg==WM_DESTROY <br>
<b> invoke DeleteObject,hBitmap </b> <br>
invoke PostQuitMessage,NULL <br>
.ELSE <br>
invoke DefWindowProc,hWnd,uMsg,wParam,lParam <br>
ret <br>
.ENDIF <br>
xor eax,eax <br>
ret <br>
WndProc endp <br>
end start
<p> ;---------------------------------------------------------------------
<br>
;
The resource script <br>
;---------------------------------------------------------------------
<br>
<b> #define IDB_MAIN 1 </b> <br>
<b> IDB_MAIN BITMAP "tweety78.bmp" </b>
<h3> Analysis:</h3>
There is not much to analyze in this tutorial ;) <br>
<blockquote><b> #define IDB_MAIN 1 </b> <br>
<b> IDB_MAIN BITMAP "tweety78.bmp" </b></blockquote>
<b>Define a constant named IDB_MAIN, assign 1 as its value. And then use that
constant as the bitmap resource identifier. The bitmap file to be included in
the resource is "tweety78.bmp" which resides in the same folder as the resource
script.</b>
<p> .if uMsg==WM_CREATE <br>
<b> invoke LoadBitmap,hInstance,IDB_MAIN </b>
<br>
<b> mov hBitmap,eax </b>
<p><b>In response to WM_CREATE, we call LoadBitmap to load the bitmap from the
resource, passing the bitmap's resource identifier as the second parameter to
the API. We get the handle to the bitmap when the function returns.</b> <br>
<b>Now that the bitmap is loaded, we can paint it in the client area of our
main window.</b>
<p> .elseif uMsg==WM_PAINT <br>
<b> invoke BeginPaint,hWnd,addr ps </b>
<br>
<b> mov hdc,eax </b>
<br>
<b> invoke CreateCompatibleDC,hdc </b>
<br>
<b> mov hMemDC,eax </b>
<br>
<b> invoke SelectObject,hMemDC,hBitmap </b>
<br>
<b> invoke GetClientRect,hWnd,addr rect </b>
<br>
<b> invoke BitBlt,hdc,0,0,rect.right,rect.bottom,hMemDC,0,0,SRCCOPY </b>
<br>
<b> invoke DeleteDC,hMemDC </b> <br>
<b> invoke EndPaint,hWnd,addr ps </b>
<p>We choose to paint the bitmap in response to WM_PAINT message. We first call
BeginPaint to obtain the handle to the device context. Then we create a compatible
memory DC with CreateCompatibleDC. Next select the bitmap into the memory DC
with SelectObject. Determine the dimension of the client area with GetClientRect.
Now we can display the bitmap in the client area by calling BitBlt which copies
the bitmap from the memory DC to the real DC. When the painting is done, we
have no further need for the memory DC so we delete it with DeleteDC. End painting
session with EndPaint.
<blockquote> .elseif uMsg==WM_DESTROY <br>
<b> invoke DeleteObject,hBitmap </b> <br>
invoke PostQuitMessage,NULL </blockquote>
When we don't need the bitmap anymore, we delete it with DeleteObject
<hr size="1">
<div align="center"> This article come from Iczelion's asm page, Welcom to <a href="http://asm.yeah.net">http://asm.yeah.net</a></div>
</body>
</html>
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -