Although
constructing a device context using MFC is easy, often
trivial, there are many situations where it is not even
necessary. Typical drawing functions (such as the OnDraw
member function in a view class) are called by the MFC
framework with a pointer to a device context object
representing a device context that is already created and
configured for use.
MFC classes
that represent device contexts are all derived from the
CDC base class. Figure 1 illustrates the hierarchy of
device context classes.
Hierarchy of device context classes.
Although
there are several classes derived from CDC, the
CDC class
itself is frequently used as a wrapper class for device
contexts. The other CDC-derived classes differ from
CDC
primarily in their constructor function and offer no extra
functionality. If you need to construct an MFC object that
is attached to an existing device context handle, you
should always use the base CDC class instead of any of the
derived classes.
The CDC
class encapsulates the functionality of the Windows device
context. And there is a lot of functionality to
encapsulate! The CDC class not only maps functions that
are directly related to configuring and managing a device
context, it also maps all GDI drawing functions. Last time
I counted, there were approximately 180 documented member
functions.
With such a
large and complex interface, where should we begin? With
the simplest. First, we review how a CDC object is created
and attached to a GDI device context.
When a CDC
object is created through its constructor function, a GDI
device context is not automatically created. Instead, it
is necessary to create a device context through the
CreateDC function or attach the CDC object to a device
context that has been created earlier.
The CreateDC
member function takes several parameters that specify the
device, the device driver software, and the port the
device is attached to. These parameters correspond to the
parameters of the GDI ::CreateDC function.
A CDC object
has not one, but two member variables that are GDI device
context handles. These are m_hDC and m_hAttribDC. Usually,
these two handles point to the same device context object.
The m_hDC handle, or output device context handle, is used
for all output operations; the m_hAttribDC handle, or
attribute device context handle, is used, in turn, for
operations that request information from the device
context.
To attach a
CDC object to a device context handle that has been
created earlier, use the Attach member function. To detach
a CDC object from a device handle, use the Detach member
function. Note that neither Detach, nor the member
functions ReleaseOutputDC and
ReleaseAttributeDC (which
reset the values of m_hDC and m_hAttribDC to NULL)
actually delete the GDI device context object. In this
case, if the device context object was created using the
GDI function ::CreateDC, it may be necessary to manually
call ::DeleteDC. Calling ::DeleteDC is not required if you
do not detach the CDC object from the device context; the
CDC destructor function makes this call automatically.
The CDC
class also has a member function DeleteDC, which can be
used to detach the CDC object from the GDI device context
and delete the device context. This function should only
be used if the device context was created using the
CreateDC member function.
Another
function that creates a device context object is CreateCompatibleDC. This function creates a memory device
context that is compatible with a given device context.
For example, applications may use this function in
conjunction with the CClientDC class to create a memory
device context that is compatible with the device context
representing the current window's client area:
CClientDC clientDC(&myWnd);
CDC memDC;
memDC.CreateCompatibleDC(&clientDC);
Subsequently,
operations such as CDC::BitBlt can be used to transfer
blocks of pixels between the two device contexts. Similar
techniques are often used in programs that perform smooth
animation; by constructing the next animation frame in a
memory device context and transferring only completed
frames to the display, you can create animations that are
free of jerkiness.
A static CDC
member function is CDC::FromHandle. This function enables
you to retrieve the address of a CDC object (if such an
object exists) that corresponds to a device context
handle. If no such CDC object exists, a temporary CDC
object is created. This function may be called as follows:
CDC *pDC = CDC::FromHandle(hDC);
Be warned
that the pointer returned by this function is not be
stored beyond immediate use. As it points to a CDC object
that may be under the control of another part of your
application, you do not usually know when the CDC object
may be destroyed, rendering the pointer returned by CDC::FromHandle invalid. Temporary CDC objects returned by
CDC::FromHandle are also deleted by the CDC::DeleteTempMap
function, which is typically called from by the idle-time
handler in your application's CWinApp object.
One more
function worth mentioning is the GetSafeHdc function. This
function returns the m_hDC member of the CDC object. This
is a "safe" function inasmuch as it can also be
used with NULL pointers; that is, the following code would
be valid and not cause an exception:
CDC *pDC = NULL;
HDC hDC = pDC->GetSafeHdc();
Free Source Code Download