Introduction to Graphics and Device Contexts
Windows graphics are accomplished using a handle to a device context,
or DC. The DC holds the current state of a generalized, or abstract, drawing
device. This includes a number of GDI objects and drawing
modes. There are currently three types of "devices" for drawing:
a video display, a printer/plotter, or a bitmap in memory.
Back to Win95 ASM Page
GDI objects
In order to draw, the DC must hold the necessary "drawing tools". Each
of these tools exist as GDI objects. You call SelectObject whenever you
need to change tools. The DC can hold only one tool of each kind. Because
the API uses the tools in the DC, complex draws may involve programming
many tool changes.
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 DC holds the state of a drawing area on the
video display. Each DC defines a clipping region--everything
drawn inside it "clips out" the graphics of any windows "under" that region.
Everything drawn outside the region is lost.
One DC commonly used by Windows programmers is the
one that allows drawing in the client area of a window. (Every
window is divided into two parts, the client and nonclient areas. The nonclient
area contains the title bar, menu, border, and scroll bars.) 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.
WM_PAINT, BeginPaint, and EndPaint
The WM_PAINT message is sent when the client area of a window requires
repainting. One such case is when portions of the client area are "uncovered"
by closing, moving, or resizing an overlapping window. Because the DC does
not hold the image that is supposed to be there, the uncovered portion
must be redrawn by the application.
When handling WM_PAINT, always call both BeginPaint
and EndPaint, even if you don't do any graphics. These functions handle
the special needs of the WM_PAINT message. If you don't handle this message,
DefWindowProc will call these functions for you.
BeginPaint returns a DC handle, and EndPaint releases
it. So it's not necessary to call GetDC and ReleaseDC. The BeginPaint and
EndPaint functions should only be used by the WM_PAINT message handler.
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 common DC handle is retrieved when GetDC (or BeginPaint)
is called. Every time it's retrieved, it references a new DC initialized
with a default set of attributes. Thus to keep memory usage low, the common
DC should be released with ReleaseDC (or EndPaint). The common DC is generally
used as a temporary DC, acquired and released by each message handler needing
a DC.
A private DC is created when a window is created.
Its handle can be retrieved with the GetDC (or BeginPaint) function, and
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.
An example program
The example program, wingdi01.asm, draws small opaque circles when
you click in the client area of the "main" window. If you cover all or
part of the window with another application window, and then move or remove
that window, you'll find the "uncovered" portion of the image is lost.
First, the application setup and cleanup.
;
; Application initialization subroutine
; Returns:
; ESI = address of a CREATEARGS structure, the CreateWindowEx argument list
; EDI = address of a WNDCLASSEX structure, the RegisterClassEx argument
; WINMAIN will set the hInstance field of the above structures
;
.data
wc WNDCLASSEX <size WNDCLASSEX,0,MainWndProc,0,0, 0, \
0,0,COLOR_WINDOW+1, 0,mainwndclsname,0>
wndmain CREATEARGS <0,mainwndclsname,maincaption, \
WS_OVERLAPPEDWINDOW+WS_VISIBLE,\
100,100,400,200, 0,0,0,0>
mainwndclsname db 'WindowGDI',0
maincaption db 'GDI Intro -- click in client area',0
.code
public InitApp,EndApp
extrn LoadCursor:near
InitApp:
mov edi,offset wc
mov esi,offset wndmain
push large IDC_ARROW
push large 0
call LoadCursor
mov [wc].wcxCursor,eax
ret
;
; Application cleanup subroutine
; Returns:
; EAX = application exit code
;
EndApp:
xor eax,eax ; assume no errors
ret
Second, the message dispatch, and the window
termination message handling.
;
; 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.
;
.code
extrn DefWindowProc:near
extrn PostQuitMessage:near
MainWndProc:
mov eax,[esp+4+4] ; message ID
cmp eax,WM_LBUTTONDOWN
je left_mouse_down
cmp eax,WM_DESTROY ; about to start window destruction
je start_destroy
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.
;
start_destroy:
push large 0
call PostQuitMessage
xor eax,eax
ret 16
Third and, finally, 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 WNDCLASSEX structure "wc" had
its style field set with CS_OWNDC, 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.
;
; -----
;
; In response to a click of the left mouse button,
; draw a circle centered on the click point.
;
.data
wndDC dd 0 ; DC handle (hDC) of window client area
.code
extrn GetDC:near
extrn ReleaseDC:near
extrn Ellipse:near
left_mouse_down:
push dword ptr [esp+4+0] ; hWnd
call GetDC
mov [wndDC],eax ; hDC for window
mov dx,[esp+4+12+2] ; HIWORD(lParam) = y
mov eax,[esp+4+12] ; LOWORD(lParam) = x
and edx,large 0FFFFh
and eax,large 0FFFFh
add edx,10
add eax,10
push edx ; y, lower right
push eax ; x
sub edx,20
sub eax,20
push edx ; y, upper left
push eax ; x
push [wndDC] ; hDC
call Ellipse
push [wndDC]
push dword ptr [esp+4+0] ; hWnd
call ReleaseDC
xor eax,eax
ret 16
Default DC attributes
When a DC is first created with CreateDC, or a common DC is retrieved with
GetDC, it is set to a default state.
-
GDI objects
-
White (background) brush
-
Black (foreground) pen
-
System font
-
System color palette
-
Clipping region = one pixel on creation, covers client area when DC is
retrieved
-
No bitmap
-
No (drawing) path
-
Drawing modes
-
OPAQUE background mode
-
R2_COPYPEN drawing mode
-
MM_TEXT (coordinate) mapping mode
-
ALTERNATE polygon fill mode
-
BLACKONWHITE (bitmap) stretching mode
-
Positions
-
Window origin = 0,0
-
Viewport origin = 0,0
-
Pen position = 0,0
-
Brush origin = 0,0
-
Other
-
Window extents = 1,1
-
Viewport extents = 1,1
-
White text background
-
Black text
-
Intercharacter spacing = 0