Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Guide to WIN32 Paint for Intermediates

0.00/5 (No votes)
4 Apr 2002 15  
Guide to understanding how Windows generates WM_PAINT messages, manages the update region for a window, and how to use all common type DCs.

Demonstration app to visualize update regions.

Introduction

Many developers are comfortable with obtaining a handle to a device context (DC) and painting to it. However, there is probably a lot of confusion in how all of the parts to Windows painting are structured. Confusion in what the different DCs are good for, and how each of these DCs can be used effectively. This article will describe in detail, how the different parts of the WIN32 paint system are combined and how to use the common and device DCs in the paint system. The memory and metafile DCs will be ignored in this article.

This tutorial will also explain how the SDK relates to each of the wrapper classes for MFC and WTL. With this knowledge, developers can then make wiser decisions on when you will create, cache, and use DCs in your Windows painting. The tutorials and code examples are written in WTL, however, the wrapper classes are very similar for both MFC and WTL.

There is a beginner tutorial that precedes this article. The preceding article covers basics of painting to a window with a DC. This article is entitled: Guide to WIN32 Paint for Beginners.

Anatomy of a Window

A window is the fundamental object through which information is conveyed to a user in WIN32 operating systems. A window is a system resource that is managed by the operating system and can be accessed by the host application with a window handle (HWND). There are many pieces of information that describe a window. This section will describe the different characteristics that relate to paint.

Physical Characteristics

The portion of a window where most of the information is displayed is called the client area. Most often, this area is represented by a rectangle. The rectangle can be retrieved from the window with this function:

::GetClientRect(HWND hWnd, RECT *pRect);

Often times, the client area will be surrounded by a region of the window called the non-client area. The non-client area encompasses the window borders, caption and the menus if any are present. A rectangle that represents the non-client area can be retrieved from the window with this function:

::GetWindowRect(HWND hWnd, RECT *pRect);

This function differs from GetClientRect in the fact that the rectangle is returned in screen coordinates, and the rectangle also encompasses the client area of the window. Therefore, if an application simply wants to access the region that represents the client area of the window, then this code must be performed:

RECT rWindow;
RECT rClient;

HRGN hRgnWindow;
HRGN hRgnClient;
HRGN hNCRgn;

//C: Get the window and client rectangles for the window.
::GetWindowRect(hWnd, &rWindow);
::GetClientRect(hWnd, &rClient);

//C: Translate the Client rectangle into screen coordinates.
POINT pt = {0,0};
::MapWindowPoints(hWnd, NULL, &pt, 1);
::OffsetRect(&rClient, pt.x, pt.y);

//C: Create regions from these two rectangles.
hRgnWindow = ::CreateRectRgnIndirect(&rWindow);
hRgnClient = ::CreateRectRgnIndirect(&rClient);
hNCRgn	   = ::CreateRectRgn(0,0,0,0);	

//C: Subtract the client region from the window region.
::CombineRgn(hNCRgn, hWindowRgn, hClientRgn, RGN_DIFF);

//C: Perform actions on the NC region.
...

//C: Free region resources.
::DeleteObject(hRgnWindow);
::DeleteObject(hRgnClient);
::DeleteObject(hNCRgn);

Here is a picture that illustrates the different regions of a window:

Client vs Non-client window regions

Update Region

The WIN32 kernel manages the state of a window. One of the most important elements of a window is its update region. The update region remembers all of the portions of the window that need to be redrawn. A region may need to be redrawn for a number of reasons:

  • Another window occludes the view of the target window.
  • The window is resized, restored from a minimized state, or maximized.
  • The window is activated or deactivated and the caption needs to be repainted.
  • The application forces the window to repaint itself.

At any point in time, the application can query the current update region for a window with this code:

//C: This code will get the entire update region.
HRGN hUpdateRgn;
hUpdateRgn = ::CreateRectRgn(0,0,0,0);

::GetUpdateRgn(hWnd, hUpdateRgn, FALSE);

//C: This code will simply retrieve the bounding box of the update region.
RECT rUpdateBox;
::GetUpdateRect(hWnd, &rUpdateBox, FALSE);

The update region can be very important for applications that would like to clip their painting code to the update region in order to improve performance.

The application can modify the update region manually, either by adding a new portion to the update region, in effect invalidating the region, or by subtracting away from the update region, or validating that region. Here is the set of functions that can be used to modify the update region.

InvalidateRect

The InvalidateRect function adds a rectangle to the specified window's update region.

BOOL InvalidateRect(
  HWND hWnd,           // handle to window
  CONST RECT *lpRect,  // rectangle coordinates
  BOOL bErase          // erase state
);

InvalidateRgn

The InvalidateRgn function invalidates the client area within the specified region by adding it to the current update region of a window.

BOOL InvalidateRgn(
  HWND hWnd,    // handle to window
  HRGN hRgn,    // handle to region
  BOOL bErase   // erase state
);

ValidateRect

The ValidateRect function validates the client area within a rectangle by removing the rectangle from the update region of the specified window.

BOOL ValidateRect(
  HWND hWnd,          // handle to window
  CONST RECT *lpRect  // validation rectangle coordinates
);

ValidateRgn

The ValidateRgn function validates the client area within a region by removing the region from the current update region of the specified window.

BOOL ValidateRgn(
  HWND hWnd,  // handle to window
  HRGN hRgn   // handle to region
);

RedrawWindow

The RedrawWindow function updates the specified rectangle or region in a window's client area. This function will modify the update region. This function can also force a repaint of the window and its children based on the flags that are set.

BOOL RedrawWindow(
  HWND hWnd,               // handle to window
  CONST RECT *lprcUpdate,  // update rectangle
  HRGN hrgnUpdate,         // handle to update region
  UINT flags               // array of redraw flags
);

Here is a list of the flags that can be used with this function and a short description of what each flag does:

  • RDW_ERASE: Causes the window to receive a WM_ERASEBKGND message when the window is repainted.
  • RDW_FRAME: Causes a WM_NCPAINT message to be sent.
  • RDW_INTERNALPAINT: Causes a WM_PAINT message to be posted to the message queue even if the update region is empty.
  • RDW_INVALIDATE: Invalidates the window with either lprcUpdate or hrgnUpdate. If both of these are NULL, then the entire window is invalidated.
  • RDW_NOERASE: Suppresses any pending WM_ERASEBKGND message.
  • RDW_NOFRAME: Suppresses any pending WM_NCPAINT messages.
  • RDW_NOINTERNALPAINT: Suppresses any internal WM_PAINT messages that are not a result of the update region.
  • RDW_VALIDATE: Validates the window with either lprcUpdate or hrgnUpdate. If both of these are NULL, then the entire window is validated.
  • RDW_ERASENOW: WM_ERASEBKGND and WM_NCPAINT messages will be sent before the function exits.
  • RDW_UPDATENOW: The window will be sent a WM_PAINT message before the function exits.
  • RDW_ALLCHILDREN: Includes any children in the repainting operations.
  • RDW_NOCHILDREN: Excludes any children from the repainting operations.

Class Styles that Affect the Update Region

There are two class styles for a window that will affect the update region for a window when the window is sized. These are CS_HREDRAW and CS_VREDRAW. These flags can be set in any combination. If the window is resized in a horizontal fashion and the CS_HREDRAW style is set, the entire display will be invalidated and redrawn. Likewise, if the window is resized vertically and the CS_VREDRAW style is set, the entire display will be invalidated. These styles can be useful for displays where the view can be scrolled.

The WM_PAINT / WM_NCPAINT Messages

A window is responsible to paint its own display. A window should paint its display in response to a WM_PAINT message. If the non-client region should be updated then the painting should occur in WM_NCPAINT. WM_PAINT and WM_NCPAINT messages are only generated when the update region is not empty. There are other ways to force a WM_PAINT message to be generated, as stated above, the RedrawWindow function can do this. It is not wise, however, to send a WM_PAINT message directly because of the nature of the update region.

When the WM_PAINT and WM_NCPAINT messages are handled, they must be handled properly. The largest risk is the mismanagement of the update region. If portions of this region are prematurely validated, then parts of the window will never be updated. On the other hand, if portions of the update region are never validated, then the system will believe that the window always needs to be updated, and will continue to send WM_PAINT messages. This will have a serious effect on performance.

The WM_ERASEBKGND Message

The WM_ERASEBKGND message is generated to clear a window's client area before that window is painted. The WM_ERASEBKGND message is generated in a few places. The most common place this message is generated is in the WM_PAINT handlers call to BeginPaint. That is another reason why it is important to call BeginPaint inside of the WM_PAINT handler.

The WM_ERASEBKGND message is passed a pre-initialized DC in the wParam parameter. An application that handles WM_ERASEBKGND should use this DC to paint the bacground, because any drawing actions that are performed will be clipped to the current update region in order to reduce flicker on the update.

Device Contexts

There are four types of DCs. The fundamental purpose of each DC is to provide a basis for drawing on a device. The area that can be drawn is determined by the type of DC that is created. This section will describe the different types of DCs that are used in painting and how they are encapsulated by MFC and WTL.

The first type of DC that will be described is the common DC. The common DC encapsulates two types of DCs, the window DC and the client DC. Then a second section will follow with Device DCs. These are DCs that represent any device on your machine, that supports some form of the Windows Graphics Device Interface (GDI). Two other types of DCs are ignored in this article, memory DCs, and metafile DCs.

A DC is an operating system resource. Because of this, it is very important that DCs are released when they are no longer required. Do not cache DCs. Each type of DC has its own method to release that DC. It is important to use the proper function because these functions act like destructors, and important shutdown operations occur in these functions for the particular type of DC. If an application performs a lengthy operation each time to initialize a DC, then a class or private DC can be created. That will be explained at the end of this section.

Common DCs

Common DCs are created from a pool of DCs that is limited by the amount of memory on the current system. Common DCs are further classified as Client and Window DCs. Client and Window DCs are very similar. The only difference between the two is that a client DC is restricted to the client area of the window, while the window DC gives the application access to both the client and the non-client areas of the window. There are two functions that allow access to a client DC (BeginPaint and GetDC,), one function to create a window DC (GetWindowDC) and one master function that will allow any sort of DC to be created for a window (GetDCEx).

Listed below is each of the functions that can be used to created a DC for a window. Any special characteristics about each function are described, as well as special uses.

Paint DC

A paint DC is represented in MFC and WTL by the CPaintDC class. This class is a wrapper around the BeginPaint function, which prepares the specified window for painting and initializes the PAINTSTRUCT structure with information about the painting.

HDC BeginPaint(
  HWND hwnd,            // handle to window
  LPPAINTSTRUCT lpPaint // paint information
);

BeginPaint prepares the window for painting by creating a client DC with a clipping region that is equivalent to the update region for the window. Then the update region is validated to prevent the generation of other WM_PAINT messages. The clipping region is set into the client DC on repaint because when the entire display is repainted, this has the effect of reducing a great portion of the flicker. However, this form of clipping will not remove all forms of flicker, especially for complicated displays that take a long period of time to repaint.

Here is the layout of the PAINTSTRUCT structure:

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

Here is a description of each of the fields:

  • hdc: The handle to the DC that is created in BeginPaint. This is the same handle that is returned from BeginPaint.
  • fErase: Indicates whether the application is responsible for erasing the background of the paint display. If the call to WM_ERASEBKGND succeeds, then this parameter will usually be FALSE.
  • rcPaint: Specifies a RECT structure that specifies the upper left and lower right corners of the rectangle in which the painting is requested. This is basically the bounding rectangle of the update region for the window.
  • fRestore: Reserved; used internally by the system.
  • fIncUpdate: Reserved; used internally by the system.
  • rgbReserved: Reserved; used internally by the system.

BeginPaint performs a few other actions while preparing the window to be painted. It will hide the caret if the current window contains a caret in order to prevent the window from painting over it. It will send a message to WM_NCPAINT in order to update the borders if necessary. After the DC has been initialized with the current clipping region, then a message to WM_ERASEBKGND will be sent. WM_ERASEBKGND will only erase the current update region.

The CPaintDC class properly disposes of the DC with a call to EndPaint. The EndPaint function marks the end of painting in the specified window. This function is required for each call to the BeginPaint function, but only after painting is complete. One extra thing that EndPaint does is restore the caret to the screen that was previously hidden in the call to BeginPaint.

BOOL EndPaint(
  HWND hWnd,                  // handle to window
  CONST PAINTSTRUCT *lpPaint  // paint data
);

The only place that BeginPaint should be called is inside of the WM_PAINT handler. This is because of the update region. If a DC is required outside of the WM_PAINT handler, GetDC should be used instead.

Client DC

A DC that paints the client area, but is not a Paint DC is referred to a ClientDC in MFC and WTL. This DC is represented by the CClientDC class. This class encapsulates a call to GetDC. This type of DC should be used any place that requires painting to the client region of a window except in the OnPaint handler. GetDC can also get a DC to paint on the entire screen if NULL is passed in as the window handle.

HDC GetDC(
  HWND hWnd   // handle to window
);

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 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 that the DC was created for.
  HDC hDC     // handle to DC
);

Window DC

A Window DC allows for the entire window, including title bar, menus, and scroll bars, to be painted. A window device context permits painting anywhere in a window, because the origin of the device context is the upper-left corner of the window instead of the client area. MFC and WTL represent this DC with the CWindowDC class, which internally calls the GetWindowDC function to create the DC. GetWindowDC can also get a DC to paint on the entire screen if NULL is passed in as the window handle.

HDC GetWindowDC(
  HWND hWnd   // handle to window
);

As with GetDC, GetWindowDC should be released with a call to ReleaseDC, which CWindowDC takes care of automatically.

GetDCEx

GetDCEx is the function that will allow the developer to create a DC that is associated with any part of a window. The three functions that were previously listed are all implemented with a call to GetDCEx. GetDCEx can also get a DC to paint on the entire screen if NULL is passed in as the window handle.

HDC GetDCEx(
  HWND hWnd,      // handle to window
  HRGN hrgnClip,  // handle to clipping region
  DWORD flags     // creation options
);

The flags parameter will determine which type of DC will be created, and how the DC will be initialized. Here is a short list of the different flags that can be used to create a DC with GetDCEx:

  • DCX_WINDOW: Returns a DC that corresponds to the window rectangle rather than the client rectangle.
  • DCX_CACHE: Returns a DC from the cache, rather than the OWNDC or CLASSDC window. Essentially overrides CS_OWNDC and CS_CLASSDC.
  • DCX_PARENTCLIP: Uses the visible region of the parent window. The parent's WS_CLIPCHILDREN and CS_PARENTDC style bits are ignored. The origin is set to the upper-left corner of the window identified by hWnd.
  • DCX_CLIPSIBLINGS: Excludes the visible regions of all sibling windows above the window identified by hWnd.
  • DCX_CLIPCHILDREN: Excludes the visible regions of all child windows below the window identified by hWnd.
  • DCX_NORESETATTRS: Does not reset the attributes of this DC to the default attributes when this DC is released.
  • DCX_LOCKWINDOWUPDATE: Allows drawing even if there is a LockWindowUpdate call in effect that would otherwise exclude this window. Used for drawing during tracking.
  • DCX_EXCLUDERGN: The clipping region identified by hrgnClip is excluded from the visible region of the returned DC.
  • DCX_EXCLUDEUPDATE: Behaves the same as DCX_EXCLUDERGN, except the update region of the window is used as input rather than the hrgnClip parameter.
  • DCX_INTERSECTRGN: The clipping region identified by hrgnClip is intersected with the visible region of the returned DC.
  • DCX_INTERSECTUPDATE: Behaves the same as DCX_INTERSECTRGN, except the update region of the window is used as input rather than the hrgnClip parameter.
  • DCX_VALIDATE: When specified with DCX_INTERSECTUPDATE, causes the DC to be completely validated. Using this function with both DCX_INTERSECTUPDATE and DCX_VALIDATE is identical to using the BeginPaint function.

As stated earlier, BeginPaint, GetDC, and GetWindowDC are all implemented in terms of GetDCEx. Listed below is a table of these flags, and the proper call that should be made to GetDCEx in order to create an equivalent DC. In all of the examples, hWnd is the handle to the target window.

  • BeginPaint
    ::GetDCEx(hWnd, NULL, DCX_INTERSECTUPDATE | 
                          DCX_VALIDATE | /* Other flags depending on class styles*/);
  • GetDC
    ::GetDCEx(hWnd, NULL, NULL);
  • GetWindowDC
    ::GetDCEx(hWnd, NULL, DCX_WIDNOW);

Class / Private DCs

It is important not to cache the common DCs in an application. How then can an application create a DC that does not have to be reinitialized each time it is called? This can be done with either a class or private DC. These two DCs can be retrieved in the same manner as the other common DCs and they do not need to be released. However, it is good practice to release these DCs as the release functions have no effect, and memory leaks will be prevented if the DCs are ever converted back to common DCs.

Class and private DCs are persistent, therefore the state of the DC will remain the same as it was in the previous call to that DC. This will allow a DC to be initialized once. This could save valuable time for applications that have lengthy DC initializations.

Given below is a short description of both the class and private DC.

  • Class DC

    A class DC is created for use for a single window class. In order to create a class DC, the window class must have the CS_CLASSDC style set. Since it is possible to create two windows of the same class on different threads, it is important to synchronize access to a class DC. Simultaneous use of a class DC on two different threads has undefined behaviour.

  • Private DC

    A private DC is created for one particular window. To create a private DC, the CS_OWNDC style must be set in the class of the window.

Device DCs

A device DC allows access to any device on the system that supports some portion of the WIN32 GDI. All types of devices can be accessed like the "DISPLAY" driver, secondary monitors, printers, plotters and any other cutting-edge device that supports GDI.

There are two steps that are required to get a handle to a device DC.

  1. Get the name of the device.
  2. Call CreateDC to create the HDC for the device.

When the application is finished with the DC, DeleteDC should be used to destroy the HDC.

Obtain Device Name

Most simply, if the application would like a DC to the primary display device, then the string "DISPLAY" can be used. However, if a DC is to be created for secondary monitor, then EnumDisplayMonitors must be used in order to get the name of the target display driver, since multi-monitor support does not exist on WIN95, this function is only valid on WIN98 and above.

In order to get the name of a printer device, the application should use EnumPrinters. This function will allow the application to search through all of the printers that are configured on the system. Important information can be queried from the printer as well in order to create a DC to it in CreateDC.

CreateDC

The CreateDC function creates a DC for a device using the specified name.

HDC CreateDC(
  LPCTSTR lpszDriver,        // driver name
  LPCTSTR lpszDevice,        // device name
  LPCTSTR lpszOutput,        // not used; should be NULL
  CONST DEVMODE *lpInitData  // optional printer data
);

The lpInitData, or DEVMODE structure is very important mainly to printer device contexts. This structure is also very complicated, however, since this article does not cover printing, that is all that will be said about DEVMODE.

CreateIC

The CreateIC function creates an information context for the specified device. The information context provides a fast way to get information about the device without creating a device context (DC). However, GDI drawing functions cannot accept a handle to an information context. This function should be followed by a call to DeleteDC when the information context is no longer needed.

HDC CreateIC(
  LPCTSTR lpszDriver,       // driver name
  LPCTSTR lpszDevice,       // device name
  LPCTSTR lpszOutput,       // port or file name
  CONST DEVMODE *lpdvmInit  // optional initialization data
);

Demonstration

The program that has been created to demonstrate the topics covered in this article will visualize the update region for the user. Other information will also be displayed in either the non-client area of the main window, or directly on one of the display drivers. One other feature of the demo application is to turn off the handling of the WM_ERASEBKGND message in order to see what effect is created.

Because of the multi-monitor testing, this application requires WIN98, WIN200 or above. This application is written in WTL, therefore the WTL header files will be required to build the source project. The WTL wrapper classes (CPaintDC, CWindowDC, etc.) will also be used in order to illustrate the use of each of the different DCs. This application will also require the version 5.0 header and lib files to compile because it uses the EnumDisplayDevices function which is only supported in WIN98 and WIN2000 or above.

Use if this application is very simple. Run the application, can force the main window to redraw itself. There are many ways to do this including:

  • Maximize / Restore the main window
  • Resize the window Horizontally / Vertically / Diagonally
  • Drag something across the window to invalidate a new region
  • Place a window in the center of the window, then activate the demo app

All of these methods to invalidate the window should be viewed. Then, each of these steps should be taken to view how things change with certain settings in the system.

  • Modify the CS_HREDRAW / CS_VREDRAW styles in the view menu
  • Modify the handling of the WM_ERASEBKGND message
  • Change the Show Window Contents While Dragging option on the view menu.

Each time that a WM_PAINT region is received, the current update region for that window will be framed with a new color. This will allow the user to visualize the update region as each new WM_PAINT message occurs. There are a few style flags that can be set for the window that will demonstrate the effects that they have on WM_PAINT messages. Here are a few screen images of the visualized update regions:

Update region created by resizing the window.

Update region created by dragging another application window across the window.

Data Log

The data log contains the important and usable values of the PAINTSTRUCT structure. Here is an image of what the data bar looks like when it is active.

Here is a description of what each of the parameters will demonstrate:

  • HDC: The value of the HDC that is allocated in WM_PAINT. Shows that a new HDC is created for each message
  • fErase: This shows whether the WM_PAINT handler is responsible for erasing the background or not. If WM_ERASEBKGND is set on the menu, then that message will be handled properly and fErase will appear as FALSE on the data bar. If WM_ERASEBKGND is not handled, then fErase will be TRUE. The view window does not handle WM_ERASEBKGND ever, so you will see a weird effect, it will look like the window is not updating properly, except for the update region will be framed properly.
  • rcPaint: The four components of this rectangle will be displayed demonstrating the bounding rectangle of the update region on the window.

Selecting No Log on the menu will hide the data bar.

If Non-client is selected on the menu, then the data bar will be painted in the border area of the window. This is done to illustrate how painting can be accomplished in the WM_NCPAINT message handler and using the CWindowDC.

This program will enumerate up to two display devices on your machine, and add them to the view menu. If you select one of these items, then the databar will be displayed in the upper-left hand corner of the monitor that the display represents. The CreateDC function is used to create the DC with the device name for that monitor. This feature was added to demonstrate getting a DC to any display monitor.

CS_HREDRAW / CS_VREDRAW Styles

As described earlier in the article, these styles affect the update region. If one of these styles is set, then when the window is resized, the corresponding style may force the entire view to be redrawn rather than simply the new update region. Change this style, and watch the effect that it has on the update region.

WM_ERASEBKGND

If this option is set, then the application will process the WM_ERASEBKGND message, effectively clearing the background during each WM_PAINT message. However, if this item is unchecked, then the application will ignore the WM_ERASEBKGND message. This will have the effect of leaving whatever invalidated the region on top of the window, rather than refreshing the display.

Also notice the fErase field value in the data bar. When WM_ERASEBKGND is handled, then fErase is FALSE indicating that the WM_PAINT routine is not responsible for initializing the drawing surface. If WM_ERASEBKGND is not processed, then fErase in the PAINTSTRUCT will be true, informing the application that it should erase the background of the display before it paints, which this application does not do in order to demonstrate the process.

Show Window Contents While Dragging

This will toggle the setting in the display properties that forces the window to repaint while a window is begin dragged. Whether it is being resized, or another window is being dragged across the top of the window, the net effect of this option being set is that more paint messages will be generated, and the update regions will be smaller, but more frequent. This application should be viewed with this option on and off.

Here is an example of the difference when resizing the window.

Update region created when full drag mode is off.  Update region created when full drag mode is on.

Shortcomings

There are two minor short comings in this demonstration application when the databar is painted on one of the display adapters. The application does not try to erase or restore the previous data when the data bar is removed. This could have been fixed by caching the region where the data bar is painted, and restoring that region when the data bar is removed. However, that would require memory DCs, and this article ignored their explanation.

When the data bar is displayed on one of the display adapters, but it is also painted onto a window from a different application, it may appear that the data bar has missed a region that it should have painted. This is actually caused by the other application receiving its WM_PAINT message after the data bar has been painted on top of it. This could be fixed by finding the window that is painting over the data bar and validating that region, or by windows hooks. However, this option has been left unexplored.

Conclusion

The WIN32 paint architecture has been designed to paint windows and controls incrementally. This increases the performance and the appearance of applications. The incremental paint process is enabled by the update region that WIN32 maintains for each and every window. WM_PAINT messages are not pushed into the message queue by the system. Instead, WM_PAINT messages are only generated when all of the other messages from the queue are processed, and the window's update region is not empty. WM_PAINT messages should be handled with the BeginPaint API, or with a CPaintDC if MFC or WTL is used.

There are other types of common DCs that can be used to paint onto the window or one of the displays. Each type of DC has a special purpose. The client DC is to paint on the client area of a window. Use the GetDC API, or the CClientDC class. A window DC allows an application to paint to the entire window. Use the GetWindowDC API, or CWindowDC class. The, GetDCEx is the API function that is at the root of all of the common DC functions. Each of the other common DCs can be created with a call to GetDCEx and the proper set of flags. If an application requires to paint directly on the desktop, then CreateDC can be used to create the DC for this purpose.

There are many different ways to paint a window in WIN32. This tutorial has presented many facts about the design, structure and process found in WIN32. Hopefully, the reader can take these facts and apply them in ways that will increase the performance and appearance of his application.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here