Tutorial 24: Windows Hooks Tutorial 25: Simple Bitmap Tutorial 26: Splash Screen

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 the example.

Theory

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:

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

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.

The other method uses a name to represent the bitmap as follows: MyBitMap bitmap "c:\project\example.bmp"

This method requires that you refer to the bitmap in your program by the string "MyBitMap" instead of a value.

Either method works fine as long as you know which method you're using.

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.

  1. call LoadBitmap to get the bitmap handle. LoadBitmap has the following definition: LoadBitmap PROTO hInstance:HINSTANCE, lpBitmapName:LPSTR
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:
  1. First Method:

    .386 .model flat, stdcall ................ .const IDB_MYBITMAP equ 100 ............... .data? hInstance dd ? .............. .code ............. invoke GetModuleHandle,NULL mov hInstance,eax ............ invoke LoadBitmap,hInstance,IDB_MYBITMAP ...........
  2. Second Method:

    .386 .model flat, stdcall ................ .data BitmapName db "MyBitMap",0 ............... .data? hInstance dd ? .............. .code ............. invoke GetModuleHandle,NULL mov hInstance,eax ............ invoke LoadBitmap,hInstance,ADDR BitmapName ...........
    1. 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.
    2. 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.
    CreateCompatibleDC PROTO hdc:HDC
    • 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.

    • 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:
    SelectObject PROTO hdc:HDC, hGdiObject:DWORD
    • 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:
    BitBlt PROTO hdcDest:DWORD, nxDest:DWORD, nyDest:DWORD, \ nWidth:DWORD, nHeight:DWORD, \ hdcSrc:DWORD, nxSrc:DWORD, \ nySrc:DWORD, dwROP:DWORD
    • hdcdest is the handle of the device context that serves as the destination of bitmap transfer operation.
    • nxDest,
      nyDest are the coordinate of the upper left corner of the output area.
    • nWidth,
      nHeight are the width and height of the output area.
    • hdcSrc is the handle of the device context that serves as the source of bitmap transfer operation.
    • nxSrc,
      nySrc are the coordinate of the upper left corner of the source rectangle.
    • dwROP 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.

When you're done with the bitmap, delete it with DeleteObject API call.

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.

Example Code:

.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 ;----------------------------------------------------------------------- ; The resource script ;----------------------------------------------------------------------- #define IDB_MAIN 1 IDB_MAIN BITMAP "tweety78.bmp"

Analysis:

There is not much to analyze in this tutorial ;)

#define IDB_MAIN 1 IDB_MAIN BITMAP "tweety78.bmp"

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.

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

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.

Now that the bitmap is loaded, we can paint it in the client area of our main window.

.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

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.

.ELSEIF uMsg==WM_DESTROY invoke DeleteObject,hBitmap invoke PostQuitMessage,NULL When we don't need the bitmap anymore, we delete it with DeleteObject

Tutorial 24: Windows Hooks Overview Tutorial 26: Splash Screen
Software » wiki » Assembler » X86 » icz » uk » tute025.html