?? lion-tut-c25.htm
字號:
<!-- saved from url=(0022)http://internet.e-mail -->
<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"><font color="#0000FF" size="3"><b>第二十五課:位圖初步</b></font></p>
<hr size="1">
<strong> </strong> 在這一課,我們將學習怎樣在程序中使用位圖。
更準確地說,我們要學習的是怎樣在一個窗口的客戶區中顯示位圖。
<h3> 理論</h3>
位圖就是存貯于電腦中的圖片。位圖文件有相當多的格式(譯者:如.BMP.JPG.GIF.PIC 等)但Windows僅
支持 Windows Bitmap Graphics 格式,即BMP文件。 本課所指的位圖也是BMP文件。
使用位圖最簡單的方法就是把它定義在資源文件(.rc)中。
定義的方法有兩種。第一種方法是把它定義為整數宏,具體如下:<br>
<blockquote>#define IDB_MYBITMAP 100 <br>
IDB_MYBITMAP <b>BITMAP</b> "c:\project\example.bmp"</blockquote>
第一行我們定義了一個值為100的整數宏。 第二行我們把這個整數宏指向所要定義的位圖,
這樣,編譯器就能知道位圖所在的路徑。<br>
另一種方法是給它起一個名字,也就是把它定義為字符串,具體如下:
<blockquote>MyBitMap <b>BITMAP</b> "c:\project\example.bmp"</blockquote>
兩種方法效果是一樣的。
選擇哪一種方法,視乎在程序中你喜歡用整數宏還是用字符串來指向位圖。 <br>
現在我們已經把位圖定義在資源文件中,下一步就是把它顯示在窗口的客戶區上。
<ol>
<li>在程序中,我們使用API函數 LoadBitmap 取得位圖句柄。 下面是 LoadBitmap 函數的
完型:</li>
</ol>
<ol>
<ol>
<b>LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LPSTR</b>
</ol>
<p><br>
該函數返回一個位圖句柄。函數有兩個參數,其中 hInstance 是程序句柄。
lpBitmapName 是位圖名字的指針(適用于第二種定義方法)。如果你使用了第一種
定義方法,你可以填入指向位圖的值或整數宏
(對應上例這個值就是100,整數宏是IDB_MYBITMAP)。下面是簡單的例子:
<ol>
<br>
第一種方法:
<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>第二種方法:
<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> 獲得一個設備文本(DC)句柄。你可以在響應WM_PAINT消息時通過API函數BeginPaint獲得。
如果在其它消息中則可以用API函數GetDC獲得。</li>
<li> 創建這個DC的內存映像。這樣做的目的是建立一張“隱藏的畫紙”,把位圖
“畫”在上面,作緩沖之用。完成這項工作后,我們就通過一個函數把“畫紙”上的位圖復制
到真正的DC中。這就是在屏幕上快速顯示圖象的雙緩沖技術。(譯者:可以減少圖象抖動)
這張“畫紙”用API函數 CreateCompatibleDC 建立,下面是它的完型:</li>
</ol>
<ol>
<ol>
CreateCompatibleDC proto hdc:HDC
</ol>
<p><br>
如果函數執行成功,將返回DC內存映像也即“畫紙”的句柄。
<li>現在我們已經有了“畫紙”,可以把位圖畫在上面了。這可以通過API函數 SelectObject 完成,
其中第一個參數是“畫紙”的句柄,第二個參數則是位圖的句柄,下面是函數的完型:</li>
</ol>
<ol>
<ol>
SelectObject proto hdc:HDC, hGdiObject:DWORD
</ol>
<li> 現在位圖已經畫在“畫紙”上了。下一步我們要把位圖復制到真正的DC中。
有很多API函數都能完成這項工作,例如 BitBlt 和 StretchBlt。
函數 BitBlt 僅僅將一個DC的內容簡單地復制到另一個DC中,而函數 StretchBlt
則能夠自動調整源DC復制內容的大小已適應目的DC的輸出區域大小,因此前者比后者速度更快。
在這里我們只使用函數 BitBlt ,下面是它的完型: </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> 目的DC的句柄。 <br>
<b>nxDest, nyDest </b>目的DC輸出區域的左上角坐標。<br>
<b>nWidth, nHeight </b> 目的DC輸出區域的長和寬。<br>
<b>hdcSrc </b> 源DC的句柄。<br>
<b>nxSrc, nySrc </b>源DC中所要復制區域的左上角坐標。 <br>
<b>dwROP </b>屏面運算碼(ROP)。該參數用以確定復制內容的顏色與輸出區域原來的顏色按哪種運算
方式處理。通常,只需要簡單地用復制內容把輸出區域覆蓋掉。
<li> 一切辦妥后,就用API函數 DeleteObject 釋放位圖對象,也就是把位圖“抹掉”。</li>
</ol>
大功告成! 現在再來回顧一下整個過程:首先,你需要把位圖定義在資源文件中。
然后,你需要在程序中載入位圖資源,并取得位圖句柄。隨后,你需要獲得位圖輸出區域的DC,
以及創建這個DC的內存映像,并把位圖放進這個DC內存映像中。最后把位圖從DC內存映像復制到
真正的DC中。
<h3> 例子:</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>
;
資源定義<br>
;---------------------------------------------------------------------
<br>
<b> #define IDB_MAIN 1 </b> <br>
<b> IDB_MAIN BITMAP "tweety78.bmp" </b>
<h3>分析:</h3>
<br>
<blockquote><b> #define IDB_MAIN 1 </b> <br>
<b> IDB_MAIN BITMAP "tweety78.bmp" </b></blockquote>
<b>定義整數宏IDB_MAIN的值為1,然后把它指向一個與資源文件處于相同目錄文件名為“tweety.bmp"的位圖。</b>
<p> .if uMsg==WM_CREATE <br>
<b> invoke LoadBitmap,hInstance,IDB_MAIN </b>
<br>
<b> mov hBitmap,eax </b>
<p><b>在處理 WM_CREATE 消息時, 我們通過API函數 LoadBitmap 載入位圖資源,并通過函數
返回值取得位圖句柄。</b> <br>
<b>然后,我們就可以把位圖畫在窗口客戶區上。</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>在本例中,我們選用在響應WM_PAINT消息時畫出位圖。首先我們通過API函數l
BeginPaint 獲得窗口客戶區的DC句柄。 接著我們通過API函數 CreateCompatibleDC 創建該DC
的內存映像,并通過API函數 SelectObject 把位圖放進內存映像中。下一步,我們通過API函數 GetClientRect
取得窗口客戶區的大小。最后,我們通過API函數 BitBlt 把位圖從DC內存映像復制到真正的客戶區DC中。
完成顯示工作后,我們通過API函數 DeleteDC 釋放DC內存映像,并用API函數 EndPaint 釋放客戶區DC,
結束畫圖工作。
<blockquote> .elseif uMsg==WM_DESTROY <br>
<b> invoke DeleteObject,hBitmap </b> <br>
invoke PostQuitMessage,NULL </blockquote>
當我們不再需要位圖時,通過API函數 DeleteObject 把它釋放。
<hr size="1">
<div align="center"> 翻譯:趙昆 Welcom to <a href="http://asm.yeah.net">http://asm.yeah.net</a></div>
</body>
</html>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -