Your browser doesn't support JavaScript The Device Context – Windows Programming

The Device Context

A device context is a Windows data structure that contains information about the drawing attributes of an output device. When an application needs to send data to a screen or printer, it must first obtain a handle to the device context (DC) of that device. Windows then fills the device context structure with the attribute values of the device being written to. The relevant API functions can then use the information in the device context to display output as required. The process of writing to the screen is known as painting.

A window may need to be painted or repainted when it is first created, when it is minimized or maximized, or as the result of some action by the user. In older, pre-Vista versions of Windows, the WM_PAINT message could also be triggered when a window that had been partially covered by another window became visible again. Usually, an application is only responsible for painting the client area. The client area is the rectangular portion of a window inside the border that does not include the window frame, caption, menu, system menu, or scroll bars. The operating system automatically paints the surrounding frame, including the title bar.

System Generated Repaint Requests

Windows does not keep a record of an application window’s contents. If any part of the client area is overwritten, Windows notifies the application by sending a WM_PAINT message to the application window, indicating that the client area needs to be repainted. The region of the application’s client area that needs updating is known as an invalid area. Windows maintains the size and coordinates of this region for each window.

BeginPaint()

The WM_PAINT message is used with the BeginPaint() function to obtain a device context. This function prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the invalidated area. The invalidated area excludes any part of the window outside the update region. The application can then use this information to redraw the window, beginning with the window’s background, which is repainted using the current brush selected in the device context.

Windows continues to place WM_PAINT messages in the message queue while an invalidated area exists. The EndPaint() function must be called after BeginPaint() to validate the client area before leaving the WM_PAINT handler block. Failure to validate the client area results in an endless WM_PAINT loop. EndPaint() marks the end of the painting operation and releases the display device context.

The prototype of the BeginPaint function is as follows-

HDC BeginPaint(HWND hwnd,LPPAINTSTRUCT lpPaint);

Where
hwnd is the handle of the window for which the device context is being obtained
lpPaint is a pointer to a PAINTSTRUCT structure.

If the function is successful, its return value is the device context. If it fails, the return value is NULL.

The prototype of PAINTSTRUCT is as follows –

typedef struct tagPAINTSTRUCT {HDC hdc;BOOL fErase;RECT rcPaint;BOOL fRestore; BOOL fIncUpdate;BYTE rgbReserved[16];} PAINTSTRUCT;

Only 3 parameters are available to the user application, the rest are filled in by windows when the user application calls BeginPaint. The hdc field is the handle to the device context returned from BeginPaint, fErase specifies whether the background needs to be redrawn and rcPaint specifies the upper left and lower right corners of the rectangle in which the ‘painting’ is requested.

The EndPaint() function is required for each call to the BeginPaint function to validate the client after the screen ‘painting’ is complete. It has the following syntax

BOOL EndPaint(HWND hwnd, const PAINTSTRUCT *lpPaint);

Where hwnd is the Handle to the window that has been ‘repainted’ and lpPaint is a Pointer to a PAINTSTRUCT structure. The return value is always nonzero.

Other Device Context-Related API Functions

GetDC()

The GetDC() function retrieves a handle to a display device context for the client area of a specified window or for the entire screen. GetDC() is usually called when an application needs to repaint the screen immediately in response to a user action that does not generate a WM_PAINT message. The GetDC() function allows an application to paint the entire client area of a window rather than only the invalid region.

The prototype for this function is:

HDC GetDC(HWND hWnd);

Where hWnd is a handle to the window whose device context is required. If this value is NULL, GetDC() retrieves the device context for the entire screen. If the function succeeds, the return value is a handle to the device context for the specified window’s client area. If the function fails, the return value is NULL.

GetWindowDC()

Similar to the GetDC() function, the GetWindowDC() function retrieves a device context (DC) for the entire application window, including non-client areas such as the title bar and scroll bars. Because the origin of the device context is the upper-left corner of the window rather than the client area, the application can paint anywhere within the window.

The prototype for this function is:

HDC GetWindowDC(HWND hWnd);

Where hWnd is a handle to the window whose device context is required. If this value is NULL, GetWindowDC() retrieves the device context for the entire screen. If the function succeeds, the return value is a handle to the device context for the specified window. If the function fails, the return value is NULL.

ReleaseDC()

The ReleaseDC() function releases a device context (DC), freeing it for use by other applications after a call to GetDC() or GetWindowDC().

The prototype for this function is:

int ReleaseDC(HWND hWnd,HDC hdc);

Where hWnd is a handle to the window whose device context is to be released, and hdc is the device context to be released. The return value indicates whether the device context was released successfully, with a value of 1 indicating success and 0 indicating failure.

ValidateRect()

Allows an application to validate a Windows region manually. The prototype for this function is

BOOL ValidateRect(HWND hWnd,const RECT *lpRect);

Where
hWnd is a handle to the window.
lpRect is a pointer to a RECT structure that contains the client coordinates of the rectangle to be removed from the update region. If the hWnd parameter is NULL the system invalidates and ‘redraws’ the entire window. If the RECT structure is NULL the entire client area is removed from the update rectangle. If the function is successful, the return value is nonzero.
If the function fails, the return value is zero.

InvalidateRect()

Allows an application to invalidate a Windows region manually and tells Windows to ‘repaint’ that region.

The prototype for this function is

BOOL InvalidateRect(HWND hWnd,const RECT *lpRect,BOOL bErase);

where
hWnd – is a handle to the window that needs to be updated. If this parameter is NULL, the system invalidates and redraws all windows, not just the windows for this application.
lpRect – is a pointer to a RECT structure containing the client coordinates of the update region. If the parameter is NULL, the entire client area is set for update.
bErase – specifies whether the background within the update region is to be erased when the update region is processed. If this parameter is TRUE, the background is erased when the BeginPaint function is called. If this parameter is FALSE, the background remains unchanged.

If the function is successful then the return value is nonzero. If the function fails, the return value is zero.

SaveDC and RestoreDC.

Each time an application requests a device context, its attributes are reset to the system defaults, and the default pen and brush are selected. To avoid this reinitialisation, the current device context state can be saved using the SaveDC() API function and later restored using the RestoreDC() API function.

Example

The following program demonstrates the WM_PAINT message by keeping a running total of client area repaints. Clicking the minimise and maximise icons or resizing the window will generate a repaint request.