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

 

Code Snippet

/*

* 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 */

 

posted @ 2021-01-01 23:08  一叶知秋,见微知著  阅读(963)  评论(0编辑  收藏  举报