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