Thread: brush handle in FillRect function - why does this work?

Hybrid View

Previous Post Previous Post   Next Post Next Post
  1. #1
    Registered User
    Join Date
    Mar 2011
    Posts
    596

    brush handle in FillRect function - why does this work?

    Code:
    HBRUSH hBrush, hDfltbrush;
    
    hDfltbrush = SelectObject(hDc, GetStockObject(DC_BRUSH));
    
    void updateclient(void)
    {
    	static PAINTSTRUCT ps;
    
    	SetDCBrushColor(hDc, 0x000000);
    	BeginPaint(hWnd, &ps);
    	FillRect(hDc, &ps.rcPaint, hBrush);
    	EndPaint(hWnd, &ps);
    }
    
    SelectObject(hDc, hDfltbrush);
    hBrush is never assigned a value anywhere in my program. Yet the function works.

    Is the hBrush argument ignored with stock objects?

  2. #2
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    There is a difference between 'working' and 'undefined behaviour returning the right result on this occasion'.

    The difference is that 'working' always does what you told it to but undefined behaviour does not always return the expected result.

    You are probably testing in a DEBUG mode and the IDE is protecting you from your mistakes (by not selecting into the DC a unititialised GDI object).
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  3. #3
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    I am asking because it could just "happen" to work now and not later.

    How do I tell if I am in debug mode? I noticed it (Pelles), but wasn't using it.

    Could it be that the handle for DC_BRUSH is zero, and hBrush was also zero?

  4. #4
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by megafiddle View Post
    Could it be that the handle for DC_BRUSH is zero, and hBrush was also zero?
    No DC_BRUSH can not be zero AND valid.

    HBRUSH is a HANDLE or pointer (memory address) so can not be NULL and valid.

    In DEBUG mode (as opposed to Release mode build) the hBrush is probably initialised to NULL by the IDE.

    FillRect() would call SelectObject() and probably is coded not to allow a NULL GDI object to be selected into a DC (as then the DC would throw errors when it tried to use the non existent GDI object).

    Code:
    //why is the PAINTSTUCT static?
    
    HDC hdcPaint = BeginPaint(hWnd, &ps);
    
    FillRect(hDc, &ps.rcPaint, hBrush);
    //should be 
    FillRect(ps.hdc, &ps.rcPaint, GetStockObject(WHITE_BRUSH));
    // or
    FillRect(hdcPaint , &ps.rcPaint, GetStockObject(WHITE_BRUSH));
    
    EndPaint(hWnd, &ps);
    //then there is no need to create or clean up any GDI objects
    BUT!

    Other events generate WM_PAINT msgs (ie another window crossing yours) with differing invalidated rects in the PAINTSTRUCT so your code will not always draw the way you expect.
    Last edited by novacain; 08-30-2011 at 09:07 PM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  5. #5
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    What is the difference between hDc and ps.hdc? Shouldn't they have the same value?

    Also would this be correct?
    Code:
    hBrush = GetStockObject(DC_BRUSH);
    
    FillRect(ps.hdc, &ps.rcPaint, hBrush);
    No reason for the static definition. Left over from something else and never fixed.

  6. #6
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by megafiddle View Post
    What is the difference between hDc and ps.hdc? Shouldn't they have the same value?
    hDc appears to be a global HDC variable (but you did not show where or how you created it).

    ps.hdc is the HDC specific to this specific dialog/window/control's screen that has just been invalidated.

    They probably contain different GDI objects.

    Your hDc is not required and, in general, global variables are bad (or show poor design). [in some cases global varaibles are required / better, but the exception proves the rule.]

    Quote Originally Posted by megafiddle View Post
    Code:
    hBrush = GetStockObject(DC_BRUSH);
    
    FillRect(ps.hdc, &ps.rcPaint, hBrush);
    Yes, that code is the interchangeable.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  7. #7
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    I don't know the exact mechanism... you stand a better chance of seeing it in Pelles Debugger than me guessing right...

    However, playing with uninitialized variables --no matter what kind, no matter where-- is playing with fire.

    I once saw the perfect definition of "Undefined Behavior"...
    "Your program will work perfectly until the day you show it to your boss."

  8. #8
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    I don't remember seeing this in particular described at msdn, but should I be doing this:

    hBrush = GetStockObject(DC_BRUSH);

    SelectObject(hDc, hBrush));

  9. #9
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    No.

    Your current paint method does not need a HDC.

    Re-read my previous posts, they show you 2 ways to get the required DC.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  10. #10
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Quote Originally Posted by novacain View Post
    No.

    Your current paint method does not need a HDC.

    Re-read my previous posts, they show you 2 ways to get the required DC.
    I fixed my updateclient, using handle returned from begin paint. No problem with that. It's
    about the other parts of the program that need an HDC. I use MoveTo, LineTo, SetPixel, etc
    in many different parts of the program.

    How do I retrieve a valid HDC to pass to these other subroutines?
    Last edited by megafiddle; 09-02-2011 at 06:07 PM.

  11. #11
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by megafiddle View Post
    How do I retrieve a valid HDC to pass to these other subroutines?
    You require a form of 'double buffering'

    The 'rules' are;

    You have a member DC (global is normally not required and can be eliminated by better design). Generally this DC is called the 'memDC' or memory DC. Making it a member means you do not need to pass the HDC, otherwise make it static in the callback and pass into the methods.
    All drawing should be done in other methods, which update your memDC and then generate a paint message.
    Your paint handler should never consist of more than a single BitBlt(), where the memDC is copied to the HDC from BeginPaint() using the rect in the PAINTSTRUCT
    You create memDC as a compatible DC in the WM_CREATE / WM_INITDIALOG msg and compatible bitmap.
    You destroy the current bitmap and create a new bitmap the correct size in WM_SIZE msgs (coping the current one with BitBlt() or StretchBlt() as required).
    You clean up the memDC in the WM_CLOSE
    You generate fast paint by using InvalidateRect() followed by UpdateWindow() [this is IMPORTANT!]
    You only invalidate the minimun rect required (not the entire client area).

    Search my posts for actual code.
    Last edited by novacain; 09-02-2011 at 10:41 PM.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  12. #12
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Thanks, I appreciate all the info.

    I can find almost all that you mentioned at msdn. I can't find anything about "member", though.
    Where can I find more info on that?

    This question came up because some examples for using the GDI from msdn and other tutorials,
    use the DC for the client area and do the drawing directly onto it.

    Should every graphics operation happen only in a memory DC then?
    Are there any cases where you can draw using the DC for the client area?

  13. #13
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Member variables are used to provide encapsulation in C++ and C#.

    Classes have 'member' variables; variables that are local to the class and are accessable in any of the classes methods / functions. [not available in C as C has no classes]
    Member variables have 'global' scope within the class but are not accessable outside an instance of the class (a class variable) unless marked as 'public'.

    [google 'member variable' or 'encapsulation' for more detail]

    Each instance of the class has its own copy of the variable (unless the member is declared as 'static').

    To answer your next question. 'Why use this feature?'
    google 'inheritance in c++'

    >>Are there any cases where you can draw using the DC for the client area?

    Yes and no.
    It all depends on the requirements of the application. If you read my posts carefully you will notice I mention your 'current paint'. This is because simple drawing (as in your example code), or drawing that does not need to be presistent, can be done in the WM_PAINT.

    >>This question came up because some examples for using the GDI from msdn and other tutorials,
    use the DC for the client area and do the drawing directly onto it.

    These are simple examples used to show basic concepts, not actual implementations used in more complex applications.
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

  14. #14
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    Doing all the drawing in a memory DC does make sense. I will be converting the program over
    to using this method at some point.

    I am still not clear on the client area HDC becoming invalid. I see how a rectangle in the client area
    becomes invalidated. But why is the handle to the client area no longer valid?

  15. #15
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    I assume you are refering to my comment;

    >>You only invalidate the minimun rect required (not the entire client area).<<

    By 'invalidate' I mean 'mark the rectangle for painting' (ie set it to be redrawn in the paint).

    You make an area 'invalid' by calling InvalidateRect(). This generates a WM_PAINT msg for the given window (HWND) and for the given area (RECT).

    You can use the whole client rect or, better, the minimum rect that includes all the changes.

    When you call BeginPaint() this invalidated RECT is copied into the PAINTSTRUCT rcPaint RECT struct.

    You then use the rcPaint RECT in your drawing (ie in the BitBlt())
    "Man alone suffers so excruciatingly in the world that he was compelled to invent laughter."
    Friedrich Nietzsche

    "I spent a lot of my money on booze, birds and fast cars......the rest I squandered."
    George Best

    "If you are going through hell....keep going."
    Winston Churchill

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. trying to loop FillRect
    By Anddos in forum Windows Programming
    Replies: 2
    Last Post: 03-27-2008, 11:49 AM
  2. Brush color
    By Gordon in forum Windows Programming
    Replies: 9
    Last Post: 04-14-2007, 06:51 AM
  3. BRUSH PEN Color
    By arjunajay in forum Windows Programming
    Replies: 2
    Last Post: 08-27-2006, 09:06 PM
  4. Ask about FillRect()
    By ooosawaddee3 in forum C++ Programming
    Replies: 0
    Last Post: 07-26-2002, 03:36 AM