<Previous Lesson

Visual Programming

Next Lesson>

Lesson#13

Graphics Device Interface

13.1 GDI (GRAPHICS DEVICE INTERFACE) 2
13.2 GDI OBJECTS AND ITS API’S 3
GDI OBJECTS CREATION 3
WHAT HAPPENS DURING SELECTION? 4
MEMORY USAGE 6
CREATING VS. RECREATING 7
STOCK OBJECTS 7
ERROR HANDLING 8
DELETION OF GDI OBJECTS 9
UNREALIZEOBJECT 10
SPECIAL CASES 11
13.3 GDI FROM THE DRIVER’S PERSPECTIVE (FOR ADVANCED USERS) 12
13.4 DEVICE CONTEXT (DC) 13
DISPLAY DEVICE CONTEXT CACHE 13
DISPLAY DEVICE CONTEXT DEFAULTS 14
COMMON DISPLAY DEVICE CONTEXT 15
PRIVATE DISPLAY DEVICE CONTEXT 16
CLASS DISPLAY DEVICE CONTEXT 17
WINDOW DISPLAY DEVICE CONTEXT 18
PARENT DISPLAY DEVICE CONTEXT 18
WINDOW UPDATE LOCK 19
ACCUMULATED BOUNDING RECTANGLE 19
13.5 STEPS INVOLVED IN OUTPUT OF A TEXT STRING IN THE CLIENT AREA OF THE
APPLICATION 20
PRINTING TEXT STRING (EXAMPLE) 20
13.6 GETDC 20
HWND 20
[IN] HANDLE TO THE WINDOW WHOSE DC IS TO BE RETRIEVED. IF THIS VALUE IS NULL,
GETDC RETRIEVES THE DC FOR THE ENTIRE SCREEN. 20
13.7 TEXTOUT 21
13.8 RELEASEDC 22
13.9 WM_PAINT 22
13.10 BEGINPAINT 23
13.11 ENDPAINT 23
13.12 WM_SIZING 24
13.13 CS_HREDRAW AND CS_VREDRAW 24
SUMMARY 24
EXERCISES 24
Graphics Device Interface 2

13.1 GDI (Graphics Device Interface)

In previous lectures we have got some understanding about GDI. In this lecture, we will
take a detail look on Graphics Device Interface and its Device independency.
The graphical component of the Microsoft® Windows™ graphical environment is the
graphics device interface (GDI). It communicates between the application and the device
driver, which performs the hardware-specific functions that generate output. By acting as
a buffer between applications and output devices, GDI presents a device-independent
view of the world for the application while interacting in a device-dependent format with
the device.
In the GDI environment there are two working spaces—the logical and the physical.
Logical space is inhabited by applications; it is the "ideal" world in which all colors are
available, all fonts scale, and output resolution is phenomenal. Physical space, on the
other hand, is the real world of devices, with limited color, strange output formats, and
differing drawing capabilities. In Windows, an application does not need to understand
the quirkiness of a new device. GDI code works on the new device if the device has a
device driver.
GDI concepts mapped between the logical and the physical are objects (pens, brushes,
fonts, palettes, and bitmaps), output primitives, and coordinates.
Objects are converted from logical objects to physical objects using the realization
process. For example, an application creates a logical pen by calling CreatePen with the
appropriate parameters. When the logical pen object is selected into a device context
(DC) using SelectObject, GDI realizes the pen into a physical pen object that is used to
communicate with the device. GDI passes the logical object to the device, and the device
creates a device-specific object containing device-specific information. During
realization, requested (logical) color is mapped to available colors, fonts are matched to
the best available fonts, and patterns are prepared for output. Font selection is more
complex than other realizations, and GDI, not the driver, performs most of the realization
work. Similarly, palette realization (done at RealizePalette time as opposed to
SelectPalette time) is done entirely within GDI. Bitmaps are an exception to the object
realization process; although they have the device-independent bitmap (DIB) logical
form, bitmap objects are always device specific and are never actually realized.
Output primitives are similarly passed as "logical" requests (to stretch the definition) to
the device driver, which draws the primitive to the best of its ability and resolution. If the
driver cannot handle a certain primitive—for example, it cannot draw an ellipse—GDI
simulates the operation. For an Ellipse call, GDI calculates a polygon that represents a
digitized ellipse. The resulting polygon can then be simulated as a polyline and a series of
scanline fills if the device cannot draw polygons itself. The application, though, does not
care what system component does the actual work; the primitive gets drawn.
Graphics Device Interface 3
An application can set up for itself any logical coordinate system, using SetMapMode,
SetWindowExt, SetWindowOrg, SetViewportExt, and SetViewportOrg. In GDI that
coordinate system is mapped to the device coordinate system, in which one unit equals
one pixel and (0,0) defines the topmost, leftmost pixel on the output surface. The device
driver sees only coordinates in its own space, whereas the application operates only in a
coordinate space of its own, disregarding the physical pixel layout of the destination.
By maintaining the two separate but linked spaces, logical for the applications and
physical for the devices, GDI creates a device-independent interface. Applications that
make full use of the logical space and avoid device-specific assumptions can expect to
operate successfully on any output device.

13.2 GDI Objects and its API’s

This topic will discuss Graphics Device Objects and the API ‘s used to create, select, get,
release, draw and delete GDI objects.

GDI objects Creation

Each type of object has a routine or a set of routines that is used to create that object.
Pens are created with the CreatePen and the CreatePenIndirect functions. An
application can use either function to define three pen attributes: style, width, and color.
The background mode during output determines the color (if any) of the gaps in any
nonsolid pen. The PS_INSIDEFRAME style allows dithered wide pens and a different
mechanism for aligning the pen on the outside of filled primitives.
Brushes are created with the CreateSolidBrush, CreatePatternBrush, CreateHatchBrush,
CreateDIBPatternBrush, and CreateBrushIndirect functions. Unlike other objects, brushes
have distinct types that are not simply attributes. Hatch brushes are special because they
use the current background mode (set with the SetBkMode function) for output.
Fonts are created with the CreateFont and CreateFontIndirect functions. An application
can use either function to specify the 14 attributes that define the desired size, shape, and
style of the logical font.
Bitmaps are created with the CreateBitmap, CreateBitmapIndirect,
CreateCompatibleBitmap, and CreateDIBitmap functions. An application can use all four
functions to specify the dimensions of the bitmap. An application uses the CreateBitmap
and CreateBitmapIndirect functions to create a bitmap of any color format. The
CreateCompatibleBitmap and CreateDIBitmap functions use the color format of the
device context. A device supports two bitmap formats: monochrome and device-specific
color. The monochrome format is the same for all devices. Using an output device
context (DC) creates a bitmap with the native color format; using a memory DC creates a
bitmap that matches the color format of the bitmap currently selected into that DC. (The
DCs color format changes based on the color format of the currently selected bitmap.)
Graphics Device Interface 4
Palette objects are created with the CreatePalette function. Unlike pens, brushes, fonts,
and bitmaps, the logical palette created with this function can be altered later with the
SetPaletteEntries function or, when appropriate, with the AnimatePalette function.
Regions can be created with the CreateRectRgn, CreateRectRgnIndirect,
CreateRoundRectRgn, CreateEllipticRgn, CreateEllipticRgnIndirect, CreatePolygonRgn,
and CreatePolyPolygonRgn functions. Internally, the region object that each function
creates is composed of a union of rectangles with no vertical overlap. Regions created
based on nonrectangular primitives simulate the complex shape with a series of
rectangles, roughly corresponding to the scanlines that would be used to paint the
primitive. As a result, an elliptical region is stored as many short rectangles (a bit fewer
than the height of the ellipse), which leads to more cumbersome and slower region
calculations and clipping. Coordinates used for creating regions are not specified in
logical units as they are for other objects. The graphics device interface (GDI) uses them
without transformation. GDI translates coordinates for clip regions to be relative to the
upper-left corner of a window when applicable. Region objects can be altered with the
CombineRgn and OffsetRgn functions.

What Happens During Selection

Selecting a logical object into a DC involves converting the logical object into a physical
object that the device driver uses for output. This process is called realization. The
principle is the same for all objects, but the actual operation is different for each object
type. When an application changes the logical device mapping of a DC (by changing the
mapping mode or the window or viewport definition), the system re-realizes the currently
selected pen and font before they are used the next time. Changing the DCs coordinate
mapping scheme alters the physical interpretation of the logical pens width and the
logical fonts height and width by essentially reselecting the two objects.
Pens are the simplest of objects. An application can use three attributes to define a logical
pen—width, style, and color. Of these, the width and the color are converted from logical
values to physical values. The width is converted based on the current mapping mode (a
width of 0 results in a pen with a one-pixel width regardless of mapping mode), and the
color is mapped to the closest color the device can represent. The physical color is a solid
color (that is, it has no dithering). If the pen style is set to PS_INSIDEFRAME and the
physical width is not 1, however, the pen color can be dithered. The pen style is recorded
in the physical object, but the information is not relevant until the pen is actually used for
drawing.
Logical brushes have several components that must be realized to make a physical brush.
If the brush is solid, a physical representation must be calculated by the device driver; it
can be a dithered color (represented as a bitmap with multiple colors that when viewed by
the human eye approximates a solid color that cannot be shown as a single pixel on the
device), or it can be a solid color. Pattern brush realization involves copying the bitmap
that defines the pattern and, for color patterns, ensuring that the color format is
compatible with the device. Usually, the device driver also builds a monochrome version
of a color pattern for use with monochrome bitmaps. With device-independent bitmap
(DIB) patterns, GDI converts the DIB into a device-dependent bitmap using SetDIBits
Graphics Device Interface 5
before it passes a normal pattern brush to the device driver. The selection of a DIB
pattern brush with a two-color DIB and DIB_RGB_COLORS into a monochrome DC is
a special case; GDI forces the color table to have black as index 0 and white as index 1 to
maintain foreground and background information. The device driver turns hatched
brushes into pattern brushes using the specified hatch scheme; the foreground and
background colors at the time of selection are used for the pattern. All brush types can be
represented at the device-driver level as bitmaps (usually 8-by-8) that are repeatedly blted
as appropriate. To allow proper alignment of these bitmaps, GDI realizes each physical
brush with a brush origin. The default origin is (0,0) and can be changed with the
SetBrushOrg function (discussed in more detail below).
The GDI component known as the font mapper examines every physical font in the
system to find the one that most closely matches the requested logical font. The mapper
penalizes any font property that does not match. The physical font chosen is the one with
the smallest penalty. The possible physical fonts that are available are raster, vector,
TrueType fonts installed in the system, and device fonts built into or downloaded to the
output device. The logical values for height and width of the font are converted to
physical units based on the current mapping mode before the font mapper examines them.
Selecting a bitmap into a memory DC involves nothing more than performing some error
checking and setting a few pointers. If the bitmap is compatible with the DC and is not
currently selected elsewhere, the bits are locked in memory and the appropriate fields are
set in the DC. Most GDI functions treat a memory DC with a selected bitmap as a regular
device DC; only the device driver acts differently, based on whether the output
destination is memory or the actual device. The color format of the bitmap defines the
color format of the memory DC. When a memory DC is created with
CreateCompatibleDC, the default monochrome bitmap is selected into it, and the color
format of the DC is monochrome. When an appropriate color bitmap (one whose color
resolution matches that of the device) is selected into the DC, the color format of the DC
changes to reflect this event. This behavior affects the result of the
CreateCompatibleBitmap function, which creates a monochrome bitmap for a
monochrome DC and a color bitmap for a color DC.
Palettes are not automatically realized during the selection process. The RealizePalette
function must be explicitly called to realize a selected palette. If a palette is realized on a
nonpalette device, nothing happens. On a palette device, the logical palette is colormatched
to the hardware palette to get the best possible matching. Subsequent references
to a color in the logical palette are mapped to the appropriate hardware palette color.
Nothing is actually realized when a clip region is selected into a DC. A copy of the region
is made and placed in the DC. This new clip region is then intersected with the current
visible region (computed by the system and defining how much of the window is visible
on the screen), and the DC is ready for drawing. Calling SelectObject with a region is
equivalent to using the SelectClipRgn function.
Graphics Device Interface 6

Memory Usage

The amount of memory each object type consumes in GDIs heap and in the global
memory heap depends on the type of the object.
This topic is discussed in Microsoft Documentation 2003 Release.
The following table describes memory used for storing logical objects.

Object type GDI heap use (in bytes) Global memory use (in
bytes)

Pen 10 + sizeof(LOGPEN) 0
Brush 10 + sizeof(LOGBRUSH) + 6 0
pattern brush same as brush + copy of bitmap
Font 10 + sizeof(LOGFONT) 0
Bitmap 10 + 18 32 + room for bits
Palette 10 + 10 4 + (10 * num entries)
rectangular region 10 + 26 0
solid complex region rect region + (6 * (num scans –1)) 0
region with hole region + (2 * num scans with hole) 0
When an object is selected into a DC, it may have corresponding physical (realized)
information that is stored globally and in GDIs heap. The table below details that use.
The size of realized versions of objects that devices maintain is determined by the device.

Object type GDI heap use (in bytes) Global memory use

pen 10 + 8 + device info 0
brush 10 + 14 + device info 0
font 55 (per realization) font data (per physical font)
bitmap 0 0
palette 0 0
region intersection of region with
visible region
0
As a result of the font caching scheme, several variables determine how much memory a
realized font uses. If two logical fonts are mapped to the same physical font, only one
copy of the actual font is maintained. For TrueType fonts, glyph data is loaded only upon
request, so the size of the physical font grows (memory permitted) as more characters are
needed. When the font can grow no larger, characters are cached to use the available
Graphics Device Interface 7
space. The font data stored for a single physical font ranges from 48 bytes for a hardware
font to 120K for a large bitmapped font.
Physical pens and brushes are not deleted from the system until the corresponding object
is deleted. The physical object that corresponds to a selected logical object is locked in
GDIs heap. (It is unlocked upon deselection.) Similarly, a font "instance" is cached in the
system to maintain a realization of a specific logical font on a specific device with a
specific coordinate mapping. When the logical font is deleted, all of its instances are
removed as well.
When the clip region intersects with the visible region, the resulting intersection is
roughly the same size as the initial clip region. This is always the case when the DC
belongs to the topmost window and the clip region is within the windows boundary.

Creating vs. Recreating

If an application uses an object repeatedly, should the object be created once and cached
by the application, or should the application recreate the object every time it is needed
and delete it when that part of the drawing is complete? Creating on demand is simpler
and saves memory in GDIs heap (objects do not remain allocated for long). Caching the
objects within an application involves more work, but it can greatly increase the speed of
object selection and realization, especially for fonts and sometimes for palettes.
The speed gains are possible because GDI caches physical objects. Although realizing a
new logical pen or brush simply involves calling the device driver, realizing a logical font
involves a cumbersome comparison of the logical font with each physical font available
in the system. An application that wants to minimize font-mapping time should cache
logical font handles that are expected to be used again. All previous font-mapping
information is lost when a logical font handle is deleted; a recreated logical font must be
realized from scratch.
Applications should cache palette objects for two reasons (both of which apply only on
palette devices). Most importantly, because bitmaps on palette devices are stored based
on a specific logical bitmap, using a different palette alters the bitmaps coloration and
meaning. The second reason is a speed issue; the foreground realization of a palette is
cached by GDI and is not calculated after the first realization. A new foreground
realization must be computed from scratch for a newly created palette (or a palette altered
by the SetPaletteEntries function or unrealized with the UnrealizeObject function).

Stock Objects

During initialization, GDI creates a number of predefined objects that any application can
use. These objects are called stock objects. With the exception of regions and bitmaps,
every object type has at least one defined stock object. An application calls the
GetStockObject function to get a handle to a stock object, and the returned handle is then
used as a standard object handle. The only difference is that no new memory is used
because no new object is created. Also, because the system owns the stock objects, an
Graphics Device Interface 8
application is not responsible for deleting the object after use. Calling the DeleteObject
function with a stock object does nothing.
Several stock fonts are defined in the system, the most useful being SYSTEM_FONT.
This font is the default selected into a DC and is used for drawing the text in menus and
title bars. Because this object defines only a logical font, the physical font that is actually
used depends on the mapping mode and on the resolution of the device. A screen DC
with a mapping mode of MM_TEXT has the system font as the physical font, but if the
mapping mode is changed or if a different device is used, the physical font is no longer
guaranteed to be the same. A change of behavior for Windows version 3.1 is that a stock
font is never affected by the current mapping mode; it is always realized as if MM_TEXT
were being used. Note that a font created by an application as a copy of a stock font does
not have this immunity to scaling.
No stock bitmap in the system is accessible by means of the GetStockObject function, but
GDI uses a default one-by-one monochrome bitmap as a stock object. This default bitmap
is selected into a memory DC during creation of that DC. The bitmaps handle can be
obtained by selecting a bitmap into a freshly minted memory DC; the return value from
the SelectObject function is the stock bitmap.

Error Handling

The two common types of errors associated with objects are failure to create and failure
to select. Both are most commonly associated with low-memory conditions.
During the creation process, GDI allocates a block of memory to store the logical object
information. When the heap is full, applications cannot create any more objects until
some space is freed. Bitmap creation tends to fail not because GDIs heap is full but
because available global memory is insufficient for storing the bits themselves. Palettes
also have a block of global memory that must be allocated by GDI to hold the palette
information. The standard procedure for handling a failed object creation is to use a
corresponding stock object in its place, although a failed bitmap creation is usually more
limiting. An application usually warns the user that memory is low when an object
creation or selection fails.
Out-of-memory conditions can also occur when a physical object is being realized.
Realization also involves GDI allocating heap memory, and realizing fonts usually
involves global memory as well. If the object was realized in the past for the same DC,
new allocation is unnecessary (see the "Creating vs. Recreating" section). If a call to
SelectObject returns an error (0), no new object is selected into the DC, and the
previously selected object is not deselected.
Another possible error applies only to bitmaps. Attempting to select a bitmap with a color
format that does not match the color format of the DC results in an error. Monochrome
bitmaps can be selected into any memory DC, but color bitmaps can be selected only into
a memory DC of a device that has the same color format. Additionally, bitmaps can be
selected only into memory DCs; they cannot be selected into a DC connected to an actual
output device or into metafile DCs.
Graphics Device Interface 9
Some object selections do not fail. Selecting a default object (WHITE_BRUSH,
BLACK_PEN, SYSTEM_FONT, or DEFAULT_PALETTE stock objects) into a screen
DC or into a screen-compatible memory DC does not fail when the mapping mode is set
to MM_TEXT. Also, a bitmap with a color format matching a memory DC always
successfully selects into that DC. Palette selection has no memory requirements and
always succeeds.

Deletion of GDI Objects

All applications should delete objects when they are no longer needed. To delete an
object properly, first deselect it from any DC into which it was previously selected. To
deselect an object, an application must select a different object of the same type into the
DC. Common practice is to track the original object that was selected into the DC and
select it back when all work is accomplished with the new object. When a region is
selected into a DC with the SelectObject or SelectClipRgn function, GDI makes a copy of
the object for the DC, and the original region can be deleted at will.
hNewPen = CreatePen(1, 1, RGB(255, 0, 0));
if (hNewPen) //if the new pen is selected then ok else do
{ hOldPen = SelectObject(hDC, hNewPen);
}
else
hOldPen = NULL; // no selection
Rectangle(hDC,x,y,ex,ey) // drawing operations
if (hOldPen)
SelectObject(hDC, hOldPen); // deselect hNewPen (if selected)
if (hNewPen)
DeleteObject(hDC, hNewPen); // delete pen if created
An alternative method is to select in a stock object returned from the GetStockObject
function. This approach is useful when it is not convenient to track the original object. A
DC is considered "clean" of application-owned objects when all currently selected objects
are stock objects. The three exceptions to the stock object rule are fonts (only the
SYSTEM_FONT object should be used for this purpose); bitmaps, which do not have a
stock object defined (the one-by-one monochrome stock bitmap is a constant object that
is the default bitmap of a memory DC); and regions, which have no stock object and have
no need for one.
Graphics Device Interface 10
hNewPen = CreatePen(1, 1, RGB(255, 0, 0));
if (hNewPen)
{
if (SelectObject(hDC, hNewPen))
{
SelectObject(hDC, GetStockObject(BLACK_PEN));
}
DeleteObject(hDC, hNewPen);
}
Note: The rumor that an application should never delete a stock object is far from the
truth. Calling the DeleteObject function with a stock object does nothing. Consequently,
an application need not ensure that an object being deleted is not a stock object.

UNREALIZEOBJECT

The UnrealizeObject function affects only brushes and palettes. As its name implies, the
UnrealizeObject function lets an application force GDI to re-realize an object from
scratch when the object is next realized in a DC.
The UnrealizeObject function lets an application reset the origin of the brush. When a
patterned, hatched, or dithered brush is used, the device driver handles it as an eight-byeight
bitmap. During use, the driver aligns a point in the bitmap, known as the brush
origin, to the upper-left corner of the DC. The default brush origin is (0,0). If an
application wants to change the brush origin, it uses the SetBrushOrg function. This
function does not change the origin of the current brush; it sets the origin of the brush for
the next time that the brush is realized. The origin of a brush that has never been selected
into a DC can be set as follows:
// Create the brush.
hBrush = CreatePatternBrush(.....);
// Set the origin as needed.
SetBrushOrg(hDC, X, Y);
// Select (and realize) the brush with the chosen origin.
SelectObject(hDC, hBrush);
Graphics Device Interface 11
If, on the other hand, the brush is currently selected into a DC, calling the SetBrushOrg
function alone accomplishes nothing. Because the new origin does not take effect until
the brush is realized anew, the application must force this re-realization by using the
UnrealizeObject function before the brush is reselected into a DC. The following sample
code changes the origin of a brush that is initially selected into a DC:
// Deselect the brush from the DC.
hBrush = SelectObject(hDC, GetStockObject(BLACK_BRUSH));
// Set a new origin.
SetBrushOrg(hDC, X, Y);
// Unrealize the brush to force re-realization.
UnrealizeObject(hBrush);
// Select (and hence re-realize) the brush.
SelectObject(hDC, hBrush);
The UnrealizeObject function can also be called for a palette object, although the effect is
a bit more subtle. (As is common with the palette functions, nothing happens on a
nonpalette device.) The function forces the palette to be realized from scratch the next
time the palette is realized, thereby ignoring any previous mapping. This is useful in
situations in which an application expects that the palette will realize differently the next
time around, perhaps matching more effectively with a new system palette and not
forcing a system palette change. Any bitmaps created with the original realization of the
palette are no longer guaranteed to be valid.

Special Cases

Palette objects are selected into DCs using the SelectPalette function. The reason for this
additional, seemingly identical, function is that palette selection has an additional
parameter that defines whether the palette is being selected as a foreground or as a
background palette, which affects palette realization on palette devices. Calling the
SelectObject function with a palette returns an error. Palettes are deleted using the
DeleteObject function.
A clip region can be selected into a DC by calling either the SelectClipRgn or the
SelectObject function. Both functions perform identically with the exception of selecting
a NULL handle in place of a region. SelectClipRgn can be used to clear the current
clipping state by calling the function as follows:
Graphics Device Interface 12
Note: Parameter description of the API’s used above, can be best found from Microsoft
site, or contact Virtual University resource.
13.3 GDI from the Driver’s Perspective (for advanced users)
Note: The documentation depicted below is for the advanced readers or those who are
interested to know more about GDI driver model. Novice can skip this topic.
GDI is the intermediary support between a Windows NT-based graphics driver and an
application. Applications call Win32 GDI functions to make graphics output requests.
These requests are routed to kernel-mode GDI. Kernel-mode GDI then sends these
requests to the appropriate graphics driver, such as a display driver or printer driver.
Kernel-mode GDI is a system-supplied module that cannot be replaced.
GDI communicates with the graphics driver through a set of graphics device driver
interface (graphics DDI) functions. These functions are identified by their Drv prefix.
Information is passed between GDI and the driver through the input/output parameters of
these entry points. The driver must support certain DrvXxx functions for GDI to call. The
driver supports GDI's requests by performing the appropriate operations on its associated
hardware before returning to GDI.
GDI includes many graphics output capabilities in itself, eliminating the need for the
driver to support these capabilities and thereby making it possible to reduce the size of
the driver. GDI also exports service functions that the driver can call, further reducing the
amount of support the driver must provide. GDI service functions are identified by their
Eng prefix, and functions that provide access to GDI-maintained structures have names in
the form XxxOBJ_Xxx.
The following figure shows this flow of communication.
Graphics Device Interface 13

Graphics Driver and GDI Interaction

More on GDI and its usage in Win32 environment contact Virtual University Resource.

13.4 Device Context (DC)

We have studied a lot about GDI and its objects and now, we will know how to display
GDI objects using Device context.
A device context is a structure that defines a set of graphic objects and their associated
attributes, as well as the graphic modes that affect output. The graphic objects include a
pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling
parts of the screen, a palette for defining the set of available colors, a region for clipping
and other operations, and a path for painting and drawing operations. The remainder of
this section is divided into the following three areas.

Display Device Context Cache

The system maintains a cache of display device contexts that it uses for common, parent,
and window device contexts. The system retrieves a device context from the cache
whenever an application calls the GetDC or BeginPaint function; the system returns the
DC to the cache when the application subsequently calls the ReleaseDC or EndPaint
function.
There is no predetermined limit on the amount of device contexts that a cache can hold;
the system creates a new display device context for the cache if none is available. Given
this, an application can have more than five active device contexts from the cache at a
time. However, the application must continue to release these device contexts after use.
Because new display device contexts for the cache are allocated in the application's heap
space, failing to release the device contexts eventually consumes all available heap space.
The system indicates this failure by returning an error when it cannot allocate space for
the new device context. Other functions unrelated to the cache may also return errors.
Graphics Device Interface
14

Display Device Context Defaults

Upon first creating a display device context, the system assigns default values for the
attributes (that is, drawing objects, colors, and modes) that comprise the device context.
The following table shows the default values for the attributes of a display device
context.

Attribute Default value

Background color Background color setting from Control Panel (typically, white).
Background mode OPAQUE
Bitmap None
Brush WHITE_BRUSH
Brush origin (0,0)
Clipping region Entire window or client area with the update region clipped, as
appropriate. Child and pop-up windows in the client area may
also be clipped.
Palette DEFAULT_PALETTE
Current pen position (0,0)
Device origin Upper left corner of the window or the client area.
Drawing mode R2_COPYPEN
Font SYSTEM_FONT
Inter character spacing 0
Mapping mode MM_TEXT
Pen BLACK_PEN
Polygon-fill mode ALTERNATE
Stretch mode BLACKONWHITE
Text color Text color setting from Control Panel (typically, black).
Viewport extent (1,1)
Viewport origin (0,0)
Window extent (1,1)
Window origin (0,0)
An application can modify the values of the display device context attributes by using
selection and attribute functions, such as SelectObject, SetMapMode, and SetTextColor.
Graphics Device Interface 15
For example, an application can modify the default units of measure in the coordinate
system by using SetMapMode to change the mapping mode.
Changes to the attribute values of a common, parent, or window device context are not
permanent. When an application releases these device contexts, the current selections,
such as mapping mode and clipping region, are lost as the context is returned to the
cache. Changes to a class or private device context persist indefinitely. To restore them to
their original defaults, an application must explicitly set each attribute.

Common Display Device Context

A common device context is used for drawing in the client area of the window. The
system provides a common device context by default for any window whose window
class does not explicitly specify a display device context style. Common device contexts
are typically used with windows that can be drawn without extensive changes to the
device context attributes. Common device contexts are convenient because they do not
require additional memory or system resources, but they can be inconvenient if the
application must set up many attributes before using them.
The system retrieves all common device contexts from the display device context cache.
An application can retrieve a common device context immediately after the window is
created. Because the common device context is from the cache, the application must
always release the device context as soon as possible after drawing. After the common
device context is released, it is no longer valid and the application must not attempt to
draw with it. To draw again, the application must retrieve a new common device context,
and continue to retrieve and release a common device context each time it draws in the
window. If the application retrieves the device context handle by using the GetDC
function, it must use the ReleaseDC function to release the handle. Similarly, for each
BeginPaint function, the application must use a corresponding EndPaint function.
When the application retrieves the device context, the system adjusts the origin so that it
aligns with the upper left corner of the client area. It also sets the clipping region so that
output to the device context is clipped to the client area. Any output that would otherwise
appear outside the client area is clipped. If the application retrieves the common device
context by using BeginPaint, the system also includes the update region in the clipping
region to further restrict the output.
When an application releases a common device context, the system restores the default
values for the attributes of the device context. An application that modifies attribute
values must do so each time it retrieves a common device context. Releasing the device
context releases any drawing objects the application may have selected into it, so the
application need not release these objects before releasing the device context. In all cases,
an application must never assume that the common device context retains non default
selections after being released.
Graphics Device Interface 16

Private Display Device Context

A private device context enables an application to avoid retrieving and initializing a
display device context each time the application must draw in a window. Private device
contexts are useful for windows that require many changes to the values of the attributes
of the device context to prepare it for drawing. Private device contexts reduce the time
required to prepare the device context and therefore the time needed to carry out drawing
in the window.
An application directs the system to create a private device context for a window by
specifying the CS_OWNDC style in the window class. The system creates a unique
private device context each time it creates a new window belonging to the class. Initially,
the private device context has the same default values for attributes as a common device
context, but the application can modify these at any time. The system preserves changes
to the device context for the life of the window or until the application makes additional
changes.
An application can retrieve a handle to the private device context by using the GetDC
function any time after the window is created. The application must retrieve the handle
only once. Thereafter, it can keep and use the handle any number of times. Because a
private device context is not part of the display device context cache, an application need
never release the device context by using the ReleaseDC function.
The system automatically adjusts the device context to reflect changes to the window,
such as moving or sizing. This ensures that any overlapping windows are always properly
clipped; that is, no action is required by the application to ensure clipping. However, the
system does not revise the device context to include the update region. Therefore, when
processing a WM_PAINT message, the application must incorporate the update region
either by calling BeginPaint or by retrieving the update region and intersecting it with the
current clipping region. If the application does not call BeginPaint, it must explicitly
validate the update region by using the ValidateRect or ValidateRgn function. If the
application does not validate the update region, the window receives an endless series of
WM_PAINT messages.
Because BeginPaint hides the caret if a window is showing it, an application that calls
BeginPaint should also call the EndPaint function to restore the caret. EndPaint has no
other effect on a private device context.
Although a private device context is convenient to use, it is expensive in terms of system
resources, requiring 800 or more bytes to store. Private device contexts are recommended
when performance considerations outweigh storage costs.
The system includes the private device context when sending the WM_ERASEBKGND
message to the application. The current selections of the private device context, including
mapping mode, are in effect when the application or the system processes these
messages. To avoid undesirable effects, the system uses logical coordinates when erasing
the background; for example, it uses the GetClipBox function to retrieve the logical
Graphics Device Interface 17
coordinates of the area to erase and passes these coordinates to the FillRect function.
Applications that process these messages can use similar techniques. The system supplies
a window device context with the WM_ICONERASEBKGND message regardless of
whether the corresponding window has a private device context.
An application can use the GetDCEx function to force the system to return a common
device context for the window that has a private device context. This is useful for
carrying out quick touch-ups to a window without changing the current values of the
attributes of the private device context.

Class Display Device Context

By using a class device context, an application can use a single display device context for
every window belonging to a specified class. Class device contexts are often used with
control windows that are drawn using the same attribute values. Like private device
contexts, class device contexts minimize the time required to prepare a device context for
drawing.
The system supplies a class device context for a window if it belongs to a window class
having the CS_CLASSDC style. The system creates the device context when creating the
first window belonging to the class and then uses the same device context for all
subsequently created windows in the class. Initially, the class device context has the same
default values for attributes as a common device context, but the application can modify
these at any time. The system preserves all changes, except for the clipping region and
device origin, until the last window in the class has been destroyed. A change made for
one window applies to all windows in that class.
An application can retrieve the handle for the class device context by using the GetDC
function any time after the first window has been created. The application can keep and
use the handle without releasing it because the class device context is not part of the
display device context cache. If the application creates another window in the same
window class, the application must retrieve the class device context again. Retrieving the
device context sets the correct device origin and clipping region for the new window.
After the application retrieves the class device context for a new window in the class, the
device context can no longer be used to draw in the original window without again
retrieving it for that window. In general, each time it must draw in a window, an
application must explicitly retrieve the class device context for the window.
Applications that use class device contexts should always call BeginPaint when
processing a WM_PAINT message. The function sets the correct device origin and
clipping region for the window, and incorporates the update region. The application
should also call EndPaint to restore the caret if BeginPaint hide it. EndPaint has no other
effect on a class device context.
The system passes the class device context when sending the WM_ERASEBKGND
message to the application, permitting the current attribute values to affect any drawing
carried out by the application or the system when processing this message. The system
Graphics Device Interface 18
supplies a window device context with the WM_ICONERASEBKGND message
regardless of whether the corresponding window has a class device context. As it could
with a window having a private device context, an application can use GetDCEx to force
the system to return a common device context for the window that has a class device
context.
Note: Use of class device contexts is not recommended.

Window Display Device Context

A window device context enables an application to draw anywhere in a window,
including the nonclient area. Window device contexts are typically used by applications
that process the WM_NCPAINT and WM_NCACTIVATE messages for windows with
custom nonclient areas. Using a window device context is not recommended for any
other purpose.
An application can retrieve a window device context by using the GetWindowDC or
GetDCEx function with the DCX_WINDOW option specified. The function retrieves a
window device context from the display device context cache. A window that uses a
window device context must release it after drawing by using the ReleaseDC function as
soon as possible. Window device contexts are always from the cache; the CS_OWNDC
and CS_CLASSDC class styles do not affect the device context.
When an application retrieves a window device context, the system sets the device origin
to the upper left corner of the window instead of the upper left corner of the client area. It
also sets the clipping region to include the entire window, not just the client area. The
system sets the current attribute values of a window device context to the same default
values as a common device context. An application can change the attribute values, but
the system does not preserve any changes when the device context is released.

Parent Display Device Context

A parent device context enables an application to minimize the time necessary to set up
the clipping region for a window. An application typically uses parent device contexts to
speed up drawing for control windows without requiring a private or class device context.
For example, the system uses parent device contexts for push button and edit controls.
Parent device contexts are intended for use with child windows only, never with top-level
or pop-up windows.
An application can specify the CS_PARENTDC style to set the clipping region of the
child window to that of the parent window so that the child can draw in the parent.
Specifying CS_PARENTDC enhances an application's performance because the system
doesn't need to keep recalculating the visible region for each child window.
Attribute values set by the parent window are not preserved for the child window; for
example, the parent window cannot set the brush for its child windows. The only property
preserved is the clipping region. The window must clip its own output to the limits of the
window. Because the clipping region for the parent device context is identical to the
Graphics Device Interface 19
parent window, the child window can potentially draw over the entire parent window, but
the parent device context must not be used in this way.
The system ignores the CS_PARENTDC style if the parent window uses a private or
class device context, if the parent window clips its child windows, or if the child window
clips its child windows or sibling windows.

Window Update Lock

A window update lock is a temporary suspension of drawing in a window. The system
uses the lock to prevent other windows from drawing over the tracking rectangle
whenever the user moves or sizes a window. Applications can use the lock to prevent
drawing if they carry out similar moving or sizing operations with their own windows.
An application uses the LockWindowUpdate function to set or clear a window update
lock, specifying the window to lock. The lock applies to the specified window and all of
its child windows. When the lock is set, the GetDC and BeginPaint functions return a
display device context with a visible region that is empty. Given this, the application can
continue to draw in the window, but all output is clipped. The lock persists until the
application clears it by calling LockWindowUpdate, specifying NULL for the window.
Although LockWindowUpdate forces a window's visible region to be empty, the function
does not make the specified window invisible and does not clear the WS_VISIBLE style
bit.
After the lock is set, the application can use the GetDCEx function, with the
DCX_LOCKWINDOWUPDATE value, to retrieve a display device context to draw over
the locked window. This allows the application to draw a tracking rectangle when
processing keyboard or mouse messages. The system uses this method when the user
moves and sizes windows. GetDCEx retrieves the display device context from the display
device context cache, so the application must release the device context as soon as
possible after drawing.
While a window update lock is set, the system creates an accumulated bounding rectangle
for each locked window. When the lock is cleared, the system uses this bounding
rectangle to set the update region for the window and its child windows, forcing an
eventual WM_PAINT message. If the accumulated bounding rectangle is empty (that is,
if no drawing has occurred while the lock was set), the update region is not set.

Accumulated Bounding Rectangle

The accumulated bounding rectangle is the smallest rectangle enclosing the portion of a
window or client area affected by recent drawing operations. An application can use this
rectangle to conveniently determine the extent of changes caused by drawing operations.
It is sometimes used in conjunction with LockWindowUpdate to determine which portion
of the client area must be redrawn after the update lock is cleared.
An application uses the SetBoundsRect function (specifying DCB_ENABLE) to begin
accumulating the bounding rectangle. The system subsequently accumulates points for
Graphics Device Interface 20
the bounding rectangle as the application uses the specified display device context. The
application can retrieve the current bounding rectangle at any time by using the
GetBoundsRect function. The application stops the accumulation by calling
SetBoundsRect again, specifying the DCB_DISABLE value.

13.5 Steps involved in output of a text string in the client area of
the application

The following points are adopted to output a text string.
1. Get the handle to the Device Context for the window’s client area from the GDI.
2. Use the Device Context for writing / painting in the client area of the window.
3. Release the Device context.
Printing Text String (Example)
HDC hdc;
hdc = GetDC(hWnd); //Get the DC
char *str=”This is Gdi program”;
TextOut(hdc,10,10,str , strlen(str)); //output a text
ReleaseDC(hWnd,hdc); //release a DC

13.6 GetDC

The GetDC function retrieves a handle to a display device context (DC) for the client
area of a specified window or for the entire screen. You can use the returned handle in
subsequent GDI functions to draw in the DC.
hDC = GetDC( hWnd );
hWnd
Handle to the window whose DC is to be retrieved. If this value is NULL, GetDC
retrieves the DC for the entire screen.
The GetDC function retrieves a common, class, or private DC depending on the class
style of the specified window. For class and private DCs, GetDC leaves the previously
assigned attributes unchanged. However, for common DCs, GetDC assigns default
attributes to the DC each time it is retrieved. For example, the default font is System,
which is a bitmap font. Because of this, the handle for a common DC returned by GetDC
Graphics Device Interface 21
does not tell you what font, color, or brush was used when the window was drawn. To
determine the font, call GetTextFace.
Note: that the handle to the DC can only be used by a single thread at any one time.
After painting with a common DC, the ReleaseDC function must be called to release the
DC. Class and private DCs do not have to be released. ReleaseDC must be called from
the same thread that called GetDC. The number of DCs is limited only by available
memory.

13.7 TextOut

The TextOut() function writes a character string at the specified location, using the
currently selected font, background color, and text color.
BOOL TextOut(
HDC hdc, // handle to DC
int nXStart, // x-coordinate of starting position
int nYStart, // y-coordinate of starting position
LPCTSTR lpString, // character string
int cbString // number of characters
);
hdc is a HANDLE to the device context.
nXStart: Specifies the x-coordinate, in logical coordinates, of the reference point that the
system uses to align the string.
nYStart: Specifies the y-coordinate, in logical coordinates, of the reference point that the
system uses to align the string.
lpString: Pointer to the string to be drawn. The string does not need to be zeroterminated,
since cbString specifies the length of the string.
cbString: Specifies the length of the string. For the ANSI function it is a BYTE count and
for the Unicode function it is a WORD count. Note that for the ANSI function, characters
in SBCS code pages take one byte each while most characters in DBCS code pages take
two bytes; for the Unicode function, most currently defined Unicode characters (those in
the Basic Multilingual Plane (BMP)) are one WORD while Unicode surrogates are two
WORDs.
The interpretation of the reference point depends on the current text-alignment mode. An
application can retrieve this mode by calling the GetTextAlign function; an application
can alter this mode by calling the SetTextAlign function.
By default, the current position is not used or updated by this function. However, an
application can call the SetTextAlign function with the fMode parameter set to
TA_UPDATECP to permit the system to use and update the current position each time
the application calls TextOut for a specified device context. When this flag is set, the
system ignores the nXStart and nYStart parameters on subsequent TextOut calls.
Graphics Device Interface 22
// Obtain the window's client rectangle
GetClientRect(hwnd, &r);
/* THE FIX: by setting the background mode
to transparent, the region is the text itself */
// SetBkMode(hdc, TRANSPARENT);
// Send some text out into the world
TCHAR text[ ] = "You can bring horse to water, but you can not make it drink";
TextOut(hdc,r.left,r.top,text, ARRAYSIZE(text)); //ARRAYSIZE is a string length

13.8 ReleaseDC

The ReleaseDC function releases a device context (DC), freeing it for use by other
applications. The effect of the ReleaseDC function depends on the type of DC. It frees
only common and window DCs. It has no effect on class or private DCs.
int ReleaseDC(
HWND hWnd, // handle to window
HDC hDC // handle to DC
);
hWnd: Handle to the window whose DC is to be released.
hDC: Handle to the DC to be released.
The application must call the ReleaseDC function for each call to the GetWindowDC
function and for each call to the GetDC function that retrieves a common DC.
An application cannot use the ReleaseDC function to release a DC that was created by
calling the CreateDC function; instead, it must use the DeleteDC function. ReleaseDC
must be called from the same thread that called GetDC.

13.9 WM_PAINT

When a minimized window is maximized, Windows requests the application to repaint
the client area.
Windows sends a WM_PAINT message for repainting a window.
Graphics Device Interface 23

13.10 BeginPaint

Begin Paint function performs following tasks.
The BeginPaint() function prepares the specified window for painting and fills a
PAINTSTRUCT structure with information about the painting.
BeginPaint() first erases the background of window’s client area by sending
WM_ERASEBKGND message.
If the function succeeds, the return value is the handle to a display device context
for the specified window.
HDC BeginPaint(
HWND hwnd, // handle to window
LPPAINTSTRUCT lpPaint // paint information
);
hwnd: Handle to the window to be repainted.
lpPaint: Pointer to the PAINTSTRUCT structure that will receive painting information.
The BeginPaint function automatically sets the clipping region of the device context to
exclude any area outside the update region. The update region is set by the InvalidateRect
or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or
any other operation that affects the client area. If the update region is marked for erasing,
BeginPaint sends a WM_ERASEBKGND message to the window.
An application should not call BeginPaint except in response to a WM_PAINT message.
Each call to BeginPaint must have a corresponding call to the EndPaint function.
If the caret is in the area to be painted, BeginPaint automatically hides the caret to
prevent it from being erased.
If the window's class has a background brush, BeginPaint uses that brush to erase the
background of the update region before returning.

13.11 EndPaint

EndPaint is used to free the system resources reserved by the BeginPaint().
This function is required for each call to the BeginPaint() function, but only after painting
is complete.
BOOL EndPaint(
HWND hWnd, // handle to window
CONST PAINTSTRUCT *lpPaint // paint data
);
hWnd: Handle to the window that has been repainted.
lpPaint: Pointer to a PAINTSTRUCT structure that contains the painting information
retrieved by BeginPaint.
Graphics Device Interface 24
Return Value: The return value is always nonzero.

13.12 WM_SIZING

Whenever a window is resized, system sends WM_SIZING message to the application
that owns the window.
In this message we can print a string each time when window is being sizing. The
following example shows our statement.
case WM_SIZING:
hDC = GetDC(hWnd);
char *str=”First GDI Call in WM_SIZING Message”;
TextOut(hDC, 0, 0, str, strlen(str));
ReleaseDC(hWnd, hDC);
break;

13.13 CS_HREDRAW and CS_VREDRAW

After specifying CS_HREDRAW and CS_VREDRAW, window will send WM_PAINT
message each time when window redraw either horizontally or vertically.
To send WM_PAINT message whenever a window is resized, we specify
CS_HREDRAW, CS_VREDRAW class styles in WNDCLASS structure while
registering the class.

Summary

In this lecture, we discussed window’s most important component—GDI (Graphics
device context) in detailed. GDI is very much useful for every programmer because it
gives platform independent interface. So whenever we want to write something on screen
or on printer we take a device context of that particular device either display or printer.
We used GetDC functions for getting device context of a display device or printer device
to output a graphics or text data. Printing or drawing can always be done through Device
context provided by Windows.
Whenever window needs to draw or paint in its client area it receives WM_PAINT
message.

Tips

1) GetDC provides you handle to the device context from the cache sometimes. So
be careful when using this handle and you must release device context after using
it or when it is useless. Do not try to delete device context handle because it is
shared to many applications so release it not delete it.
Graphics Device Interface 25
2) Try to perform painting in client area always in WM_PAINT message.
(recommended)

Exercises

1. Write an application that uses Private Device Context. Using that device
context, display center aligned text.
2. Before starting of above application, show a dialog box which gives
option to the user to change background brush.

<Previous Lesson

Visual Programming

Next Lesson>

Home

Lesson Plan

Topics

Go to Top

Next Lesson
Previous Lesson
Lesson Plan
Topics
Home
Go to Top