December 20th, 2021

Why do I have to add one when setting a class background brush to a system color?

When you register a window class, you can specify that the background color is a system color by adding one to the system color index, and then casting the result to HBRUSH:

WNDCLASS wc;
...
wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);

Why do we add one?

To make sure that the result is not zero.

The COLOR_SCROLL­BAR system color is index zero. If we didn’t add one to the system color indices, then an attempt to set the background color to the scroll bar color would end up with (HBRUSH)0, which is a null pointer. When the system saw that you set hbrBackground to a null pointer, it wouldn’t know whether you meant the window to have no background color (null pointer), or whether you wanted it to have the system scroll bar color (COLOR_SCROLL­BAR).

In other words, adding one ensures that the space of “system colors smuggled inside a brush handle” does not overlap with the space of regular brush handles.

In retrospect, this was one of those “too clever” hacks born out of the days of 16-bit Windows and systems with only 256KB of memory. Nowadays, we would say, “Just set the background to GetSysColorBrush(COLOR_WINDOW).” But back then, GetSysColorBrush(COLOR_WINDOW) didn’t exist.

Topics
Code

Author

Raymond has been involved in the evolution of Windows for more than 30 years. In 2003, he began a Web site known as The Old New Thing which has grown in popularity far beyond his wildest imagination, a development which still gives him the heebie-jeebies. The Web site spawned a book, coincidentally also titled The Old New Thing (Addison Wesley 2007). He occasionally appears on the Windows Dev Docs Twitter account to tell stories which convey no useful information.

8 comments

Discussion is closed. Login to edit/delete existing comments.

  • Brian Ross

    GetSysColorBrush says the following:

    An application must not register a window class for a window using a system brush. To register a window class with a system color, see the documentation of the hbrBackground member of the WNDCLASS or WNDCLASSEX structures.

    And WNDCLASS/WNDCLASSEX doesn't make any mention of GetSysColorBrush() for .hbrBackground.

    ...

    Can we confirm that this is ok?

    WNDCLASS wc;
    wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);

    ...

    It seems strange that it would not be ok - but then what is the GetSysColorBrush warning...

    Read more
    • Sigge Mannen

      I think this was covered by Raymond way back as well. Normally system brushes aren’t released, but they do when a window class registered with one is unregistered.
      At least that’s how i remember it

      • Scarlet Manuka

        Indeed, the documentation for the hbrBackground member of WNDCLASSEX (as pointed to above) says as much:

        “The system automatically deletes class background brushes when the class is unregistered by using UnregisterClass. An application should not delete these brushes.”

        It makes sense that you would not want one of the system brushes to be deleted when your class was unregistered!

      • Tim Weis

        The documentation for GetSysColorBrush has the following remark as well:

        "Although you don't need to delete the logical brush that GetSysColorBrush returns, no harm occurs by calling DeleteObject."

        I'm confused now. So either the documentation wasn't consistently updated as the implementations changed over time, or UnregisterClass does something other than calling DeleteObject on the class background brush. Part of me wants the latter to be true, with a future blog entry detailing "The sad history of UnregisterClass".

        Read more
      • Chris Iverson

        It's all straightfoward to me. This is the sequence of events, as I understand it.

        WNDCLASS was created first, documented to use the COLOR constant + 1 to represent a system color.

        If you pass a brush in to RegisterClass, then UnregisterClass will delete the brush when it unregisters that class. Therefore, YOU shouldn't delete the brush out from under it, it will take care of it for you

        GetSysColorBrush() came later, and was documented as...

        Read more
      • Sigge Mannen

        Man, i’m confused too now 😀 Raymond, can you explain it?

      • Brian Ross

        So what is the best practice here? 🙂

        WNDCLASS wc;
        wc.hbrBackground = GetSysColorBrush(COLOR_WINDOW);

        Is the code that I would want to write… (which avoids the +1/reinterpret_cast nonsense).

        But is this “safe” according to the documentation despite the warning that I quoted in my original post?

  • Peter Cooper Jr.

    Raymond also covered this back in 2014: https://devblogs.microsoft.com/oldnewthing/20140305-00/?p=1593

    Honestly I wouldn’t mind a “best-of” “classic article” “rerun” featured every day: there’s a lot of treasure buried in the past, what, almost 18 years of content?