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

  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
    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."

  5. #5
    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));

  6. #6
    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

  7. #7
    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.

  8. #8
    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

  9. #9
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    My function above is only called when a WM_PAINT is received.
    Far as I can tell it works ok.

    Did you mean there would be problems if it were used independantly from receiving a WM_PAINT?


    Also, my hDc is a global, and it did happen to be the handle for that device context.

    But how would I get it to the various functions that needed it, if it was declared in WinMain,where
    it is assigned it's value?
    The chain of funtion calls to the functions that require it begin in the callback procedure, WndProc.
    Last edited by megafiddle; 08-31-2011 at 04:35 PM.

  10. #10
    train spotter
    Join Date
    Aug 2001
    Location
    near a computer
    Posts
    3,868
    Quote Originally Posted by megafiddle View Post
    Did you mean there would be problems if it were used independantly from receiving a WM_PAINT?
    Your global HDC will be invalid in many circumstances (ie if the window changes shape / size).

    Quote Originally Posted by megafiddle View Post
    But how would I get it to the various functions that needed it, if it was declared in WinMain,where
    it is assigned it's value?
    WinMain is not the right place to create the HDC, as the window may not be full 'setup' intill the WM_CREATE / WM_INITDIALOG msg is processed (ie most windows are first created with a default size and then sent msgs to set them to the correct / desired size.)

    If you are using double buffering then you use private member variables or properties to hold the memory DC (back buffer).

    Otherwise you pass the HDC into the function from your callback.

    When processing a simple paint (like yours) you use the HDC in the PAINTSTRUCT or returned by the call to BeginPaint(). Note that this HDC is only valid until the call to EndPaint().
    "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

  11. #11
    Registered User
    Join Date
    Mar 2011
    Posts
    596
    So do I need to use:

    hDc = GetDC(hWnd);

    or something, every time the window changes?

    Does GetDC return the new and current handle?

    I've been using that same global hDc for all my drawing. Would have never known,
    so far, that it wasn't actually "working". I only caught the uninitialized hBrush while
    looking for something else.

  12. #12
    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

  13. #13
    Banned
    Join Date
    Aug 2010
    Location
    Ontario Canada
    Posts
    9,547
    Quote Originally Posted by megafiddle View Post
    I've been using that same global hDc for all my drawing. Would have never known,
    so far, that it wasn't actually "working". I only caught the uninitialized hBrush while
    looking for something else.
    Definition of "Undefined Behaviour"...
    1) Code that works perfectly until someone else tries to use it.
    2) Code that works perfectly until you show it to your boss.
    3) Bugs and problems that only show up after you've taken delivery of 50,000 CDs.

  14. #14
    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.

  15. #15
    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

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