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