7

If I need to use double buffering, I need to suppress WM_ERASEBKGND message.

I can handle WM_ERASEBKGND and return immediately. But can I set the WNDCLASS/WNDCLASSEX's hbrBackground to NULL and not handle the WM_ERASEBKGND message? Is this a correct way?

EFanZh
  • 2,357
  • 3
  • 30
  • 63

2 Answers2

7

Yes, setting hbrBackground to NULL is an appropriate way to avoid implementing a no-op WM_ERASEBKGND handler.

When you pass WM_ERASEBKGND on to DefWindowProc, it checks the background brush in the window's class. If there is one, it fills the dirty region with it. If the background brush is null, it does nothing and returns. That's essentially the same as having your own do-nothing WM_ERASEBKGND handler.

The return value from the WM_ERASEBKGND handler affects the fErase field of the PAINTSTRUCT you get when WM_PAINT calls BeginPaint. The WM_PAINT handler is supposed to check fErase to find out whether it needs to erase the background itself or if it was already done by WM_ERASEBKGND. (Though I've never actually seen anyone check it.) If you let DefWindowProc handle WM_ERASEBKGND it will return TRUE if it has a color number or brush and FALSE if the hbrBackground is NULL.

Adrian McCarthy
  • 45,555
  • 16
  • 123
  • 175
  • 2
    Note that you are __still__ sent a `WM_ERASEBKGND` then. Only difference is if you don't handle it, nothing happens (safe to ignore). – Damon Aug 22 '12 at 13:11
  • Are you certain that this is a kosher method? Do you know why [Raymond Chen seems to make a distinction](https://blogs.msdn.microsoft.com/oldnewthing/20140305-00/?p=1593/) between using `NULL` and the hollow brush? – jamesdlin Dec 07 '16 at 23:42
  • Yes, it's kosher. Of `hbrBackground`, MSDN says, "When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area." – Adrian McCarthy Dec 08 '16 at 00:07
  • @AdrianMcCarthy I meant: are you sure that it's kosher to set `hbrBackground` to `NULL` *and* to not handle `WM_ERASEBKGND` (the original question). The MSDN documentation you cited does say "an application *must* paint its own background ...". (Your comments on [my answer](http://stackoverflow.com/a/41029315/179715) make sense, though.) – jamesdlin Dec 08 '16 at 00:54
  • "...whenever it is requested to paint in its client area." Which suggests that doing it in WM_PAINT is fine. WM_ERASEBKGND is sent by the BeginPaint call (if the invalid region is also marked for erasure), so it's already happening in the WM_PAINT handler. And to make sure theory matches practice, I've just tested it. if hbrBackground is NULL, DefWindowProc's handling for WM_ERASEBKGND is to do nothing but return FALSE. – Adrian McCarthy Dec 08 '16 at 00:59
1

I believe that it is more correct to set hbrBackground = GetStockObject(HOLLOW_BRUSH) than it is to set it to NULL.

An article on Raymond Chen's The Old New Thing makes a distinction:

If you don't want automatic background drawing, then pass the hollow brush. If you want custom background drawing, then pass NULL as the brush.

The MSDN documentation for WNDCLASS's hbrBackground member says:

When this member is NULL, an application must paint its own background whenever it is requested to paint in its client area. To determine whether the background must be painted, an application can either process the WM_ERASEBKGND message or test the fErase member of the PAINTSTRUCT structure filled by the BeginPaint function.

And the MSDN documentation for WM_ERASEBKGND says:

The DefWindowProc function erases the background by using the class background brush specified by the hbrBackground member of the WNDCLASS structure. If hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.

My interpretation is that setting hbrBackground to NULL and then neglecting to handle WM_ERASEBKGND not meant to be strictly legal (but probably works); hbrBackground = NULL is a promise that you will handle WM_ERASEBKGND yourself and not let DefWindowProc try to paint with a null pointer.

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • I think you're over analyzing it. Setting hbrBackground to NULL does the right thing. You can either fill the background yourself by handling WM_ERASEBKGND or you can do it in WM_PAINT. DefWindowProc for WM_ERASEBKGND returns TRUE if there was a brush (or color) specified and it filled the area. It returns FALSE if hbrBackground was NULL. No harm. – Adrian McCarthy Dec 08 '16 at 00:15
  • 1
    I think the distinction is what happens to the fErase member of the PAINTSTRUCT you get from BeginPaint. If you have a hollow brush selected, the default WM_ERASEBKGND handler will fill with the hollow brush and return TRUE (meaning "I erased the background). That causes the fErase member to be FALSE, so the rest of the WM_PAINT handler isn't tricked into doing it's own erasing. If you have NULL, the default WM_ERASEBKGND handler does nothing and returns FALSE ("I did NOT erase the background"), which causes the fErase member to be TRUE. – Adrian McCarthy Dec 08 '16 at 00:35
  • 1
    In the documentation for PAINTSTRUCT, under fErase, it says: "The application is responsible for erasing the background if a window class is created without a background brush." So it's legit to not have a backround brush at all. Here, "the application" refers to the WM_PAINT handler, because by the time you get the PAINTSTRUCT from BeginPaint, WM_ERASEBKGND has come and gone. Yes, you're still responsible for painting the background, but the WM_PAINT handler is a legit place to do it. – Adrian McCarthy Dec 10 '16 at 14:37