Thread: Background color in RGB

  1. #1
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401

    Background color in RGB

    Is anyone able to tell me how to convert the background brush of a window into RGB? By this I mean that when I set the hbrBackground member of the WNDCLASSEX structure, eg, to (HBRUSH)(COLOR_BTNFACE+1), I'd like to know what that color is in RGB. Thanks for any ideas.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  2. #2
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    You can use the GetSysColor() API routine to obtain the RGB of any of the "system" colours.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  3. #3
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    So does this mean that to find out the background color in RGB I can do the following?

    Code:
    COLORREF crf;
    
    crf=GetSysColor((int)GetClassLong(hwnd,GCL_HBRBACKGROUND)-1);
    And if that's correct, is it the best way to do it?
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  4. #4
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    That won't work because GCL_HBRBACKGROUND returns a handle to the brush, not the colour that the brush is loaded with. You could do...
    Code:
    RGBBuf = GetSysColor(COLOR_BTNFACE + 1);
    ... although I find adding a number to a constant distasteful.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  5. #5

  6. #6
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    Actually adrianxw, it did work. If you can set something to a system color using the COLOR_+1 defines, than you should logically be able to do the reverse. Give it a try, it really does work. Although the practicality is somewhat limited, like everything I program...
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  7. #7
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    Not sure I'm actually with you Ben. The call I showed will work, yes, I know, that's why I put it there!

    The reason I dislike the COLOR_ +1 business is that for example COLOR_BTNFACE is defined to have the value 15. So you add one to that, you get 16 which is the value of COLOR_BTNSHADOW another valid system colour. What happens if MS change the defined values, or you pick the last valid system colour? Then you add 1 to it and may end up with an undefined colour and unpredictable results.

    It works, but I don't happen to like it.

    Or did you mean something else?
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  8. #8
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    That won't work because GCL_HBRBACKGROUND returns a handle to the brush, not the colour that the brush is loaded with. You could do...
    That's what I was referring to. The code I posted that resulted in the quote above actually worked fine. But you're right about defined values changing, it's a bad system. Thanks for the help.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  9. #9
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    I just tried this for myself and it does not work for me.

    What you might find is that the handle, (which is only an integer after all), returned by GetClassLong() happens to fall within the same range as the integers representing the system colours. Thus GetSysColor() may not report a failure, (by returning 0), but also, may not return the actual background colour, and indeed, may not return the same colour every time.

    When I ran it, GetSysColor() returned 0.
    Code:
        hBrush = CreateSolidBrush((COLORREF)0x000000FF);
        
        WinClass.cbSize = sizeof(WNDCLASSEX);   
        WinClass.hInstance = hThisInst;
        WinClass.lpszClassName = "Window";
        WinClass.lpfnWndProc = WindowFunc; 
        WinClass.style = 0;     
        WinClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
        WinClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
        WinClass.hCursor = LoadCursor(NULL, IDC_ARROW);
        WinClass.lpszMenuName = NULL; 
        WinClass.cbClsExtra = 0; 
        WinClass.cbWndExtra = 0;
        WinClass.hbrBackground = hBrush;
    So my background colour should be 0x000000FF, but...
    Code:
        case WM_PAINT:
            hDC = BeginPaint(hWnd,
                             &PaintStruct);
    
            i = (int)GetClassLong(hWnd,GCL_HBRBACKGROUND);
            GetObject((HBRUSH)i,sizeof(LOGBRUSH),&LogBrush);
            Colour = GetSysColor(i);
            EndPaint(hWnd,
                     &PaintStruct);
            break;
    i is 0x36100057. Passing that as a handle to GetObject correctly shows the colour as 0x000000FF, but passing the same number to GetSysColor() return 0.

    If it is working for you, great, but I wouldn't rely on it.
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  10. #10
    jasondoucette.com JasonD's Avatar
    Join Date
    Mar 2003
    Posts
    278
    This is how you set a new background brush of a window to a specific RGB value:

    Code:
    SetClassLong (hwnd, GCL_HBRBACKGROUND, (LONG) CreateSolidBrush (RGB (rvalue,gvalue,bvalue)));
    You should place this inside of a DeleteObject() call so that you can delete the old brush, which is returned by SetClassLong, once you type cast it into an HBRUSH. Also, remember to call DeleteObject in the WM_DESTROY message to delete the brush before the program exists.

  11. #11
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    JasonD, if you delete the brush straight away, won't that mean you will lose the background brush before it's even used? When I was first trying brushes out, which was yesterday, I experimented on where to delete it. I found that you can only delete it after you never need to use it again, or else the background reverts to plain white. So how can you delete it straight away?

    Also, why delete it twice?

    Also, remember to call DeleteObject in the WM_DESTROY message to delete the brush before the program exists.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  12. #12
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    adrianxw, the issue is that you set hbrBackground to a handle, not a pre-defined system color value. My code will tell you what system color the background is PROVIDED you actually set the hbrBackground member to a predefined system color value in the first place, like so:

    Code:
    wcx.hbrBackground=(HBRUSH)16;
    .
    .
    .
    intValue=GetClassLong(hwnd,GCL_HBRBACKGROUND);
    intValue will equal 16, I guarantee it. But I admit that the applications are limited.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  13. #13
    It's full of stars adrianxw's Avatar
    Join Date
    Aug 2001
    Posts
    4,829
    Okay, you're casting a constant to the handle, in which case the "handle" is not really a handle at all, in that you couldn't draw with it for example, you can, of course, now use GetSysColor().
    Wave upon wave of demented avengers march cheerfully out of obscurity unto the dream.

  14. #14
    mustang benny bennyandthejets's Avatar
    Join Date
    Jul 2002
    Posts
    1,401
    Agreed.
    [email protected]
    Microsoft Visual Studio .NET 2003 Enterprise Architect
    Windows XP Pro

    Code Tags
    Programming FAQ
    Tutorials

  15. #15
    jasondoucette.com JasonD's Avatar
    Join Date
    Mar 2003
    Posts
    278
    Originally posted by bennyandthejets
    JasonD, if you delete the brush straight away, won't that mean you will lose the background brush before it's even used? When I was first trying brushes out, which was yesterday, I experimented on where to delete it. I found that you can only delete it after you never need to use it again, or else the background reverts to plain white. So how can you delete it straight away?

    Also, why delete it twice?
    Good questions. Let me give you an example program, which will answer all of your questions at the same time (maybe not in the order you like them to be answered, so please look at all of it before replying):

    The background brush is first set in WinMain() like so:
    Code:
    wndclass.hbrBackground = CreateSolidBrush ( RGB(0,0,0) ) ;
    // note that we do not save the handle to the brush.
    // This is ok, since we can obtain it later.
    In WM_DESTROY, we destroy this brush like so:
    Code:
    DeleteObject (
    	(HBRUSH) SetClassLong (
    		hwnd, 
    		GCL_HBRBACKGROUND, 
    		(LONG) GetStockObject (WHITE_BRUSH)
    	)
    ) ;
    // this code replaces the old brush with a stock brush
    // (one that doesn't need to be deleted, which is normally
    // what WinMain() sets the background brush to).
    // NOTE: that SetClassLong() changes a 32-bit value in
    // a window class structure, and we are using it to change
    // the brush handle.  SetClassLong() returns the value that
    // we are replacing - the handle of the brush that is already
    // there.  DeleteObject() takes one parameter - the old
    // brush's handle, and deletes it.
    This nifty code allows us to change the brush whenever we feel like it, since the WM_DESTROY message will always destroy the currently used brush for the background, which is the only brush ever avaiable at any given time (i.e. the others are destroyed as soon as they are not used):
    Code:
    DeleteObject (
    	(HBRUSH) SetClassLong (
    		hwnd, 
    		GCL_HBRBACKGROUND, 
    		(LONG) CreateSolidBrush (RGB (Rvalue,Gvalue,Bvalue))
    	)
    ) ;
    // NOTE: that DeleteObject() deletes the brush already set
    // as the background brush, as SetClassLong() returns this
    // handle.  SetClassLong replaces the old brush handle
    // with the new brush handle that it makes with
    // CreateSolidBrush() (that will be
    // later deleted with this same function call OR the one
    // in WM_DESTROY - either case, we needn't save the
    // brush handle).  
    // Rvalue,Gvalue,Bvalue = 0..255, which is
    // the 24-bit color of the new brush you want.
    // RGB() is a macro, as I'm sure you know, that makes a
    // COLORREF valye from these three bytes.
    Therefore, we do not delete any brush twice, and we never delete a brush until it is no longer used.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. OpenGL: Pixel addition
    By Hunter2 in forum Game Programming
    Replies: 4
    Last Post: 12-15-2008, 02:36 PM
  2. Writing Background RGB to file
    By SwiftOutlaw in forum Windows Programming
    Replies: 8
    Last Post: 03-27-2005, 06:56 AM
  3. Windows background color
    By Exile in forum Windows Programming
    Replies: 2
    Last Post: 01-23-2005, 07:55 AM
  4. Stopwatch program (need help!)
    By modnar in forum C Programming
    Replies: 9
    Last Post: 03-22-2004, 12:42 AM
  5. Detect Close of a background process
    By Schwarzhelm in forum C Programming
    Replies: 1
    Last Post: 11-05-2003, 01:46 AM