A device context is a Windows data structure containing 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 a device context or DC of that device. Windows then fills the device context structure with the attribute values of the device being written to. The information in the device context can then be used along with the relevant API function to display output as required. The process of writing to the screen is known as ‘painting’.

A window might need to be 'painted' or 'repainted' when the window is first created when the window is uncovered from behind another window, or as the result of some action by the user. Usually, an application will only be responsible for painting the client area. The client area is the rectangular part of a window inside the window’s border that doesn’t include the window frame, caption, menu, system menu, or scrollbars. The operating system automatically paints the surrounding frame, including the title bar.

System Generated Repaint Requests

Windows does not keep a record of the application window content. If by some action, the client area or part of the client area is overwritten then Windows will inform the application that the client area needs to be ‘repainted’ by posting a WM_PAINT message to the application window. The region of the application client that needs updating is known as an “invalid area”. Windows maintains the size and coordinates of this region for each window.

BeginPaint()

The BeginPaint() function is generally used with the WM_PAINT message to obtain a device context. It prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the invalidated area which will exclude the area outside the update region. The device context returned from a call to BeginPaint is saved in an HDC datatype. The application can then use these values to redraw the window starting with the window's background which is repainted with the current brush selected in the device context.

Windows continues sending WM_PAINT messages to the message queue if there’s an invalidated area. 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 will result in an endless WM_PAINT loop. The EndPaint marks the end of the screen validation and releases the display device context.

The prototype of the BeginPaint function is as follows-

HDC BeginPaint(HWND hwnd,LPPAINTSTRUCT lpPaint);

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

The return value of the function, if successful is a device context. If the function 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 the entire screen. GetDC is usually called when an application needs to 'repaint' the screen instantly and occurs in response to an action by the user that does not generate a WM_Paint message. The GetDC method 'paints' the Windows client area and not merely the invalid region. The prototype for this function is

HDC GetDC(HWND hWnd);

Where hWnd is a handle to the required Windows device context. 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 DC for the required window’s client area. If the function fails, the return value is NULL.

GetWindowDC()

Similar to the GetDC function the GetWindowDC() function retrieves the device context (DC) for the entire application window, including non-client areas such as the title and scroll bars. Since the origin of the device context will be the upper-left corner of the window instead of the client area the application will be able to paint anywhere in the application window. The prototype for this function is

HDC GetWindowDC(HWND hWnd);

Where hWnd is a handle to the required Windows device context. 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 DC for the required window’s client area. If the function fails, the return value is NULL.

ReleaseDC()

Releases a device context (DC), freeing it for use by other applications after a call to GetDC or GetWindowsDC. The prototype is

int ReleaseDC(HWND hWnd,HDC hdc);

Where hWnd is a handle to the window whose DC is to be released and hdc is the device context to be released. The return value indicates whether the DC was released with a value of 1 indicating success and a value of zero 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 default and the default pen and brush will be used. To avoid this reinitialisaton, the current device context state can be saved with the API function SaveDC() and restored with the API function RestoreDC().

Example

The following short program demonstrates the WM_PAINT message by keeping a running total of the times the client area has been repainted. The repaint request can be generated by dragging another window over the application window or clicking the minimise and maximise icons.

Display Download