WNDCLASS成员变量hbrBackground赋值时候的奇怪用法说明。
最近有个需求是需要一个窗口的背景色。发现RegisterClass函数在注册窗口的时候就可以指定背景色,所以直接修改这个值不就可以了吗?
然后看了WTL中窗口类的注册宏,发现里头的用法很奇怪。
怎么把一个颜色值+1后强制转换成了画刷句柄。很好奇这是怎么回事儿,然后就开始这个问题的探索。
立马查询了官方文档:
https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-registerclassa
https://docs.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-wndclassa
官方文档说的很清楚了:
hbrBackground
Type: HBRUSH
A handle to the class background brush. This member can be a handle to the physical brush to be used for painting the background, or it can be a color value. A color value must be one of the following standard system colors (the value 1 must be added to the chosen color). If a color value is given, you must convert it to one of the following HBRUSH types:
- COLOR_ACTIVEBORDER
- COLOR_ACTIVECAPTION
- COLOR_APPWORKSPACE
- COLOR_BACKGROUND
- COLOR_BTNFACE
- COLOR_BTNSHADOW
- COLOR_BTNTEXT
- COLOR_CAPTIONTEXT
- COLOR_GRAYTEXT
- ......
也就是说,这个画刷句柄,你要么传入一个物理画刷句柄。或者也可以传入一个颜色值,但是这个颜色值需要+1,然后再转换成画刷句柄值,然后对颜色值也有要求,必须是系统定义的颜色值,后面列举出来了。
那问题就来了,问什么传入画刷句柄的API可以传入颜色值呢?还有这么奇怪的要求。
google 查询了一番。基本上有了答案。
https://stackoverflow.com/questions/15658341/color-window-in-hbrbackground
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e4fd1c4b-4407-4743-a74f-7d78338c17d2/hbrbackground-hbrushcolorwindow1-what-is-1-for?forum=vcgeneral
基于上面两篇文章的讲解和自己的理解,总结如下:
1.为了方便直接把颜色值当做句柄值来绘制背景,相当让这个API更方便的使用了,所以微软这么做了。
2.为什么要加1呢?因为COLOR_SCROLLBAR定义为0(参考附录),如果不加1就分不清楚是COLOR_SCROLLBAR还是一个空的画刷了,所以需要加1。这个定义可能是比较早,所以是为了像老代码兼容。
3.这么简单的加1有什么问题吗?没有,因为系统定义的颜色值都很小,而画刷句柄的值一般都很大,是一个内存指针。他们两个值不可能重叠。所以微软知道哪个范围的值是真实的画刷句柄,哪个是传入的系统颜色值。
(注:0-0xFFFF的地址是空指针赋值分区,如何地址都不能访问,系统颜色值没有超过0xFFFF。)
4.自己随便写一个RGB的颜色值,然后也加1,再转换成画刷句柄可以吗?不可以,只支持系统颜色值。原因可以参考第3条的解释。这也说明了一个问题:如果想要用自定义的颜色值来当背景画刷句柄,需要创建一个真实的物理画刷句柄。比如CreateSolidBrush等。
实际上,很多API需要HBRUSH的地方,都可以使用系统颜色值加1的方式来实现。
比如FillRect函数:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-fillrect
官方也是说可以传入系统颜色值加1的。
上面的文档也说明了系统颜色值有哪些。GetSysColor函数支持哪些就有哪些。
可以参考GetSysColor的官方文档中的详细列表:https://docs.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-getsyscolor
附录:系统颜色值定义:
These system colors are defined in winuser.h
/*
* Color Types
*/
#define CTLCOLOR_MSGBOX 0
#define CTLCOLOR_EDIT 1
#define CTLCOLOR_LISTBOX 2
#define CTLCOLOR_BTN 3
#define CTLCOLOR_DLG 4
#define CTLCOLOR_SCROLLBAR 5
#define CTLCOLOR_STATIC 6
#define CTLCOLOR_MAX 7
#define COLOR_SCROLLBAR 0
#define COLOR_BACKGROUND 1
#define COLOR_ACTIVECAPTION 2
#define COLOR_INACTIVECAPTION 3
#define COLOR_MENU 4
#define COLOR_WINDOW 5
#define COLOR_WINDOWFRAME 6
#define COLOR_MENUTEXT 7
#define COLOR_WINDOWTEXT 8
#define COLOR_CAPTIONTEXT 9
#define COLOR_ACTIVEBORDER 10
#define COLOR_INACTIVEBORDER 11
#define COLOR_APPWORKSPACE 12
#define COLOR_HIGHLIGHT 13
#define COLOR_HIGHLIGHTTEXT 14
#define COLOR_BTNFACE 15
#define COLOR_BTNSHADOW 16
#define COLOR_GRAYTEXT 17
#define COLOR_BTNTEXT 18
#define COLOR_INACTIVECAPTIONTEXT 19
#define COLOR_BTNHIGHLIGHT 20
#if(WINVER >= 0x0400)
#define COLOR_3DDKSHADOW 21
#define COLOR_3DLIGHT 22
#define COLOR_INFOTEXT 23
#define COLOR_INFOBK 24
#endif /* WINVER >= 0x0400 */
#if(WINVER >= 0x0500)
#define COLOR_HOTLIGHT 26
#define COLOR_GRADIENTACTIVECAPTION 27
#define COLOR_GRADIENTINACTIVECAPTION 28
#if(WINVER >= 0x0501)
#define COLOR_MENUHILIGHT 29
#define COLOR_MENUBAR 30
#endif /* WINVER >= 0x0501 */
#endif /* WINVER >= 0x0500 */
#if(WINVER >= 0x0400)
#define COLOR_DESKTOP COLOR_BACKGROUND
#define COLOR_3DFACE COLOR_BTNFACE
#define COLOR_3DSHADOW COLOR_BTNSHADOW
#define COLOR_3DHIGHLIGHT COLOR_BTNHIGHLIGHT
#define COLOR_3DHILIGHT COLOR_BTNHIGHLIGHT
#define COLOR_BTNHILIGHT COLOR_BTNHIGHLIGHT
#endif /* WINVER >= 0x0400 */