Introduction to Graphics

Ultimately, all graphics under Windows are accomplished via a device context, or DC. The DC is the information about a drawing environment. This includes a reference to a drawing surface (a so-called "device"), some assigned GDI objects (drawing tools), and a few drawing modes.  There are currently three types of devices: a video display device, a hardcopy device (printer or plotter), and a virtual device (a bitmap in memory). [ Back to Win32 ASM Page ]

Display device context (video display DC)

The DC used with a video display is also known as a display device context. It allows you to draw images on the video display.
    Each display DC holds the state of a drawing area on the video display. Each DC defines a clipping region--everything "drawn" outside the region is ignored, and effectively removed (or "clipped out").
    One DC commonly used by Windows programmers is the one that allows drawing in the client area of a window. When needed, a handle to this DC is normally retrieved in a message handler after it is invoked, and released before the message handler terminates. If the message is WM_PAINT, the two functions used are BeginPaint and EndPaint. Otherwise, the two functions are GetDC and ReleaseDC.

Common and private DC

The two primary types of display device contexts are common and private. (The third supported type, class, is obsolete.) When retrieving the DC handle, the DC will be private if the window class was registered with the CS_OWNDC class style, otherwise it will be common. A DC handle is retrieved by calling GetDC. (When responding to WM_PAINT, we must call BeginPaint.)
    If the DC is common, it references a new DC initialized with a default set of drawing tools and modes. This DC should be released by calling ReleaseDC before exiting the window procedure. (When responding to WM_PAINT, we must call EndPaint.)
    If a private DC is created when a window is created, it's not necessary to call ReleaseDC. Unlike the common DC, it is not reinitialized on retrieval. As a result, you avoid the need to reset all your drawing tools and modes with every message requiring graphics. However, if you display a lot of windows simultaneously, giving every window a private DC will use a lot of memory.

An example program

The example program, windraw1.asm, draws a circle when you click in the client area of the "main" window.

Creation, loop, and dispatch

        .386
        .model  flat

        ; If using TLINK32, don't include vclib.inc
        include vclib.inc    ; Microsoft VC++ .lib link names

        include win32hst.inc ; constants, structures, and entry names

        .data
        align   4
wcx     dd      size WNDCLASSEX           ; cbSize
        dd      CS_VREDRAW or CS_HREDRAW  ; style
        dd      WndProc                   ; lpfnWndProc
        dd      0,0                       ; cbClsExtra, cbWndExtra
        dd      0                         ; hInstance
        dd      0                         ; hIcon
        dd      0                         ; hCursor
        dd      COLOR_WINDOW+1            ; hbrBackground
        dd      0                         ; lpszMenuName
        dd      wndclsname                ; lpszClassName
        dd      0                         ; hIconSm

wndclsname db 'windraw',0

        .code

        public _start
        extrn   GetModuleHandle:near
        extrn   LoadIcon:near,LoadCursor:near
        extrn   RegisterClassEx:near

_start:
        push    large 0         ; NULL string pointer means
        call    GetModuleHandle ; get HINSTANCE/HMODULE of EXE file
        mov     [wcx.wcx_hInstance],eax

        push    large IDI_WINLOGO
        push    large 0         ; hInstance, 0 = stock icon
        call    LoadIcon
        mov     [wcx.wcx_hIcon],eax

        push    large IDC_ARROW
        push    large 0         ; hInstance, 0 = stock cursor
        call    LoadCursor
        mov     [wcx.wcx_hCursor],eax

        push    offset wcx
        call    RegisterClassEx

        .data
        align   4
cwargs   dd   0                  ; dwExStyle
         dd   wndclsname         ; lpszClass
         dd   wnd_title          ; lpszName
         dd   WS_VISIBLE or WS_OVERLAPPED or WS_SYSMENU or WS_THICKFRAME \
                or WS_MINIMIZEBOX or WS_MAXIMIZEBOX  ; style
         dd   100                ; x
         dd   100                ; y
         dd   200                ; cx (width)
         dd   200                ; cy (height)
         dd   0                  ; hwndParent
         dd   0                  ; hMenu
         dd   0                  ; hInstance
         dd   0                  ; lpCreateParams

msgbuf MSG      <>

wnd_title db 'Draw a circle',0

        .code

        extrn   CreateWindowEx:near
        extrn   GetMessage:near,DispatchMessage:near
        extrn   ExitProcess:near

        sub     esp,48            ; allocate argument list
        mov     esi,offset cwargs ; set block move source
        mov     edi,esp           ; set block move destination
        mov     ecx,12            ; number of arguments
        rep movsd
        mov     eax,[wcx.wcx_hInstance]
        mov     [esp+40],eax      ; set hInstance argument in stack
        call    CreateWindowEx

msg_loop:
        push    large 0         ; uMsgFilterMax
        push    large 0         ; uMsgFilterMin
        push    large 0         ; hWnd (filter), 0 = all windows
        push    offset msgbuf   ; lpMsg
        call    GetMessage      ; returns FALSE if WM_QUIT
        or      eax,eax
        jz      end_loop

        push    offset msgbuf
        call    DispatchMessage

        jmp     msg_loop

end_loop:
        push    large 0 ; (error) return code
        call    ExitProcess
;
; The window procedure...where messages for one class of windows
;   are processed.
;
; Parameters are hWnd, message, wParam, lParam.
;   hWnd is the window receiving this message.
;   message is the message ID.
;   wParam and lParam depend on the message ID.
;
; Must preserve EBX, ESI, and EDI.
;
        extrn   DefWindowProc:near,PostQuitMessage:near

        .code
WndProc:
        mov     eax,[esp+4+4]   ; message ID
        cmp     eax,WM_DESTROY  ; about to start window destruction
        je      on_destroy
        cmp     eax,WM_LBUTTONDOWN      ; left mouse button is clicked
        je      on_left_mouse_button_down
        jmp     DefWindowProc   ; delegate other message processing
;
; Process WM_DESTROY.  Sent after window is removed from screen, but
; before any destruction begins.
;
; Return zero if processed.
;
; Must preserve EBX, ESI, and EDI.
;
on_destroy:
        push    large 0
        call    PostQuitMessage

        xor     eax,eax
        ret     16

Drawing

Here is the heart of this example -- graphics at the click of a mouse button. It shows the acquisition (GetDC) and release (ReleaseDC) of a common DC. If the WNDCLASSEX structure "wc" had CS_OWNDC or'ed into the style field, the GetDC would get the handle of a private DC, and ReleaseDC would do nothing -- in other words, the call to ReleaseDC could be eliminated.
    To draw a circle, the Ellipse function is called with the coordinates of the enclosing rectangle.
; Process WM_LBUTTONDOWN.  Left mouse button has been pressed.
;
; wParam is mouse flags.
; lParam is y:x (client coordinates).
;
; Return zero if processed.
;
; Must preserve EBX, ESI, and EDI.
;
        .data
        align   4
wndDC   dd 0            ; DC handle (hDC) of window client area

        .code

        extrn GetDC:near,ReleaseDC:near
        extrn Ellipse:near

on_left_mouse_button_down:
        push    dword ptr [esp+4+0]     ; hWnd
        call    GetDC
        mov     [wndDC],eax             ; hDC for window

        push    large 150               ; y, lower right
        push    large 150               ; x
        push    large 50                ; y, upper left
        push    large 50                ; x
        push    [wndDC]                 ; hDC
        call    Ellipse

        push    [wndDC]
        push    dword ptr [esp+4+0]     ; hWnd
        call    ReleaseDC

        xor     eax,eax
        ret     16

        end     _start