СТАТЬИ > Уроки Iczelion'а

Win32 API. Урок 25. Простой битмэп

На этом уроке мы научимся использовать битмэпы в своих программах. Если быть более точным, мы научимся отображать битмэп в клиентской области нашей программы. Скачайте пример здесь.

ТЕОРИЯ

Битмэпы можно представлять себе как изображения, хранимые в компьютере. На компьютерах используется множество различных форматов изображений, но Windows естественным образом поддерживает только формат растровых изображений Windows (.bmp). На этом уроке, когда речь будет идти о битмэпах, будет подразумеваться именно этот формат. Самый простой способ использовать битмэп - это использовать его как ресурс. Есть два способа это выполнить. Можно включить битмэп в файл определения ресурсов (.rc) следующим образом:

       #define IDB_MYBITMAP   100
       IDB_MYBITMAP  BITMAP  "c:\project\example.bmp"

В этом методе для представления битмэпа используется константа. В первой строчке просто задаётся константа с именем IDB_MYBITMAP и значением 100. По этому имени мы и будем обращаться к битмэпу в нашей программе. В следующей строке объявляется битмэп-ресурс. Таким образом, компилятор узнаёт, где ему искать собственно сам .bmp файл.

В другом методе для представления битмэпа используется имя, делается это следующим образом:

       MyBitMap  BITMAP "c:\project\example.bmp"

При использовании этого метода, в вашей программе вам придётся ссылаться на битмэп по строке "MyBitMap", а не по значению.

Оба метода прекрасно работают, главное - определиться, какой именно вы будете использовать. После включения битмэпа в файл ресурсов, можно приступить к его отображению в клиентской области нашего окна:

Вот и всё! Если коротко, то сначала добавьте битмэп в файл ресурсов. После этого загрузите его из ресурсов с помощью LoadBitmap. Вы получите хэндл битмэпа. Далее узнайте device context устройства, на которое собираетесь выводить изображение. Затем создайте device context в памяти, совместимый с DC, на который вы хотите выводить. "Выберите" (select) битмэп на 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_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.bmp" и располагается в той же папке, что и файл ресурсов.

      .if uMsg==WM_CREATE
         invoke LoadBitmap,hInstance,IDB_MAIN
         mov hBitmap,eax

После получения сообщения WM_CREATE мы вызываем 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. Для этого мы сначала вызываем BeginPaint и получаем хэндл DC. Затем создаем совместимый memory DC вызовом CreateCompatibleDC. Далее "выбираем" битмэп в память с помощью SelectObject. Определяем размеры клиентской области окна через GetClientRect. Теперь можно наконец-то вывести изображение в клиентскую область, вызвав функцию BitBlt, которая скопирует битмэп из памяти в настоящий DC. По завершению рисования мы удаляем DC в памяти вызовом DeleteDC, так как он нам больше не нужен. Подаём сигнал о завершении отрисовки окна с помощью EndPaint.

        .elseif uMsg==WM_DESTROY
         invoke DeleteObject,hBitmap
         invoke PostQuitMessage,NULL

По окончанию работы удаляем битмэп посредством DeleteObject.

  [C] Iczelion, пер. WD-40

© 2002-2004 wasm.ru - all rights reserved and reversed