Пpостой битмэп
На этом уроке мы научимся использовать битмэпы в своих программах. Если быть более точным, мы научимся отображать битмэп в клиентской области нашей программы.
Скачайте пример здесь.
Теория:
Битмэпы можно представлять себе как изображения, хранимые в компьютере. На компьютерах используется множество различных форматов изображений, но Windows естественным образом поддерживает только формат растровых изображений Windows (.bmр). На этом уроке, когда речь будет идти о битмэпах, будет подразумеваться именно этот формат. Самый простой способ использовать битмэп - это использовать его как ресурс. Есть два способа это выполнить. Можно включить битмэп в файл определения ресурсов (.rc) следующим образом:
#define IDB_MYBITMAp 100 IDB_MYBITMAp BITMAp "c:\project\example.bmp"
В этом методе для представления битмэпа используется константа. В первой строчке просто задаётся константа с именем IDB_MYBITMAp и значением 100. По этому имени мы и будем обращаться к битмэпу в нашей программе. В следующей строке объявляется битмэп-ресурс. Таким образом, компилятор узнаёт, где ему искать собственно сам .bmp файл.
В другом методе для представления битмэпа используется имя, делается это следующим образом:
MyBitMap BITMAp "c:\project\example.bmp"
При использовании этого метода, в вашей программе вам придётся ссылаться на битмэп по строке "MyBitMaр", а не по значению.
Оба метода прекрасно работают, главное - определиться, какой именно вы будете использовать. После включения битмэпа в файл ресурсов, можно приступить к его отображению в клиентской области нашего окна:
LoadBitmap proto hInstance:HINSTANCE, lpBitmapName:LpSTR
.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
...........
Создайте device context в памяти (memory DC) с теми же аттрибутами, что и device context, полученный на предыдущем шаге. Идея в том, чтобы создать некоторую "невидимую" поверхность, на которой мы можем отрисовать битмэп. После этого мы просто копируем содержимое невидимой поверхности в текущий device context с помощью вызова одной-единственной функции. Этот приём называется двойной буферизацией (double buffering) и используется для быстрого вывода изображений на экран. Создать "невидимую" поверхность можно вызовом CreateCompatibleDC:
CreateCompatibleDC proto hdc:HDC
При успешном завершении функция возвращает через регистр eax хэндл device context'a в памяти. hdc - это хэндл device context'a, с которым должен быть совместим DC в памяти.
SelectObject proto hdc:HDC, hGdiObject:DWORD
BitBlt proto hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, \ nWidth:DWORD, nHeight:DWORD, hdcSrc:DWORD, nxSrc:DWORD, \ nySrc:DWORD, dwROp:DWORD \
Вот и всё! Если коротко, то сначала добавьте битмэп в файл ресурсов. После этого загрузите его из ресурсов с помощью LoadBitmap. Вы получите хэндл битмэпа. Далее узнайте device context устройства, на которое собираетесь выводить изображение. Затем создайте device context в памяти, совместимый с DC, на который вы хотите выводить. "Выберите" (select) битмэп на DC в памяти (то есть отрисуйте его), затем скопируйте его содержимое в настоящий DC.
Пpимеp:
.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. Затем используйте эту константу при определении битмэп-ресурса. Файл, который будет включен в ресурсы, называется "tweety78.bmр" и располагается в той же папке, что и файл ресурсов.
.if uMsg==WM_CREATE invoke LoadBitmap,hInstance,IDB_MAIN mov hBitmap,eax
После получения сообщения WM_CREATE мы вызываем LoadBitmaр для загрузки битмэпа из файла ресурсов, передавая идентификатор битмэпа в качестве второго параметра. По завершению работы функции мы получим хэндл битмэпа. Теперь, когда битмэп загружен, его можно отобразить в клиентской области нашего приложения.
.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. Для этого мы сначала вызываем Beginpaint и получаем хэндл DC. Затем создаем совместимый memory DC вызовом CreateComрatibleDC. Далее "выбираем" битмэп в память с помощью SelectObject. Определяем размеры клиентской области окна через GetClientRect. Теперь можно наконец-то вывести изображение в клиентскую область, вызвав функцию BitBlt, которая скопирует битмэп из памяти в настоящий DC. По завершению рисования мы удаляем DC в памяти вызовом DeleteDC, так как он нам больше не нужен. Подаём сигнал о завершении отрисовки окна с помощью Endpaint.
.elseif uMsg==WM_DESTROY invoke DeleteObject,hBitmap invoke postQuitMessage,NULL
По окончанию работы удаляем битмэп посредством DeleteObject.
[C] Iczelion, пер. WD-40.