CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Page 1 of 2 12 LastLast
Results 1 to 15 of 26

Thread: Repaint failure

  1. #1
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Repaint failure

    I'm using VC++ 6 on Win2k, and I am testing on XP and Vista for compatibility problems. My app has a graphic window which is not repainting properly when my app has lost focus and other windows are dragged across it. When my app is topmost, there is no problem. When a child dialog dragged across, there is no problem.

    Since the repaint does occur (albiet corrupted), I know WM_PAINT is being handled. What is baffling to me is that the problem only happens in XP and Vista, not Win2K.

    I am drawing to a buffer in memory and blitting to the screen:
    Code:
    case WM_PAINT:
    	dc = BeginPaint(hWsbox, &ps);
    	SelectObject(dc, hBitmap);
    	BitBlt(dc, 0, 0, selarr_wid, selarr_hgt,
    		sdc, 0, scroll ? si.nPos * (SEL_RY + fhgt) : 0, SRCCOPY);
    	EndPaint(hWsbox, &ps);
    	break;
    Can someone give me a clue?
    Attached Images Attached Images  

  2. #2
    Join Date
    Apr 2009
    Posts
    598

    Re: Repaint failure

    I experienced similar problems and my (not the best I think) solution was to add an InvalidateRect() like this:
    Code:
    case WM_PAINT:
            InvalidateRect(hWsbox, NULL, TRUE);
    	dc = BeginPaint(hWsbox, &ps);
    	SelectObject(dc, hBitmap);
    	BitBlt(dc, 0, 0, selarr_wid, selarr_hgt,
    		sdc, 0, scroll ? si.nPos * (SEL_RY + fhgt) : 0, SRCCOPY);
    	EndPaint(hWsbox, &ps);
    	break;

  3. #3
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Repaint failure

    Interesting idea. It seems redundant to put InvalidateRect() in the paint handler, since the rect is already invalid in order for the WM_PAINT to be sent.

    But I tried that, and it actually prevents the corruption problem, at the expense of horrendous flicker from the background erasure. I tried it both ways, erase flag true or false, and it doesn't matter, it flickers badly both ways.

    Thanks for the idea, it may lead to something that works.

  4. #4
    Join Date
    Apr 2009
    Posts
    598

    Re: Repaint failure

    I forgot to say I prevent or alleviate the flicker problem with
    Code:
          case WM_ERASEBKGND:
             return(1); // Prevent erasing the background to reduce flickering
             break;

  5. #5
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Repaint failure

    Code:
          case WM_ERASEBKGND:
             return(1);
    Can't do that or the rest of the window will have no background. There is an area with buttons that needs the background. I discovered that by trying it a while ago.

  6. #6
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Repaint failure

    I've been trying stuff, and have arrived at code that has no repaint corruption on Vista now, as well as Win2K. XP shows some occasional flickering in the bitmap window, but not horrendous, and no corruption. So maybe I'll just live with it for now.
    Code:
    	case WM_ACTIVATE:
    		if (LOWORD(wParam) != WA_INACTIVE) InvalidateRect(hWnd, 0, 0);
    		break;
    
    	case WM_PAINT:
    		if (GetActiveWindow() != hWnd) InvalidateRect(hWnd, &re, 0);
    		dc = BeginPaint(hWsbox, &ps);
    		SelectObject(dc, hBm);
    		BitBlt(dc, ps.rcPaint.left,
    			ps.rcPaint.top, 
    			ps.rcPaint.right - ps.rcPaint.left,
    			ps.rcPaint.bottom - ps.rcPaint.top,
    			sdc, ps.rcPaint.left,
    			ps.rcPaint.top + (scroll ? si.nPos * (SEL_RY + fhgt) : 0),
    			SRCCOPY);
    		EndPaint(hWsbox, &ps);
    		break;
    
    	case WM_ERASEBKGND:
    //		if (GetActiveWindow() != hWnd) return 1;
    		break;

  7. #7
    Join Date
    Nov 2007
    Posts
    613

    Re: Repaint failure

    1. You forget to deselect the hBitmap from the dc at the end. That will create problems for sure.

    2. The fact that WM_PAINT is sent doesn't mean necessarily that it will repaint the whole window. It will repaint only the invalid region of the window. You don't need to bother about that, the OS will properly invalidate any area in need to be repainted.

    3. A few questions:
    a. Are you sure the right bitmap is selected all the time in the sdc ?
    b. Is the bitmap containing the right image ?
    c. Are coordinates and sizes properly calculated ?
    d. Is your bitmap large enough to cover the whole window ?

    4. Never call Invalidate from the inside of the WM_PAINT message handler.

    5. Are you sure that you comply with all the requirements to deal with graphic functions ?
    - Each SelectObject must have a pair that deselects that object when no longer needed
    - Each bitmap creation function must have a DeleteObject pair to delete it when no longer needed
    - Each dc created must be deleted/released when no longer necessary.
    DC function pairs:
    BeginPaint with EndPaint
    GetDC with ReleaseDC
    CreateCompatibleDC with DeleteDC

    When deleting a dc, none of the objects created by you must be left selected in it. (That's what you did wrong here. And probably there are more in the code you didn't post.)

    You should have:
    Code:
    BeginPaint....
    .....
    HBITMAP hBitmapOld = SelectObject(dc, hBitmap);
    .....
    
    SelectObject(dc, hBitmapOld);
    EndPaint...
    Failure to comply with all these requirements will lead to serious problems. Just creating graphic objects and not disposing them properly will fill all the GDI memory with useles objects. You will run out of the GDI memory with unpredictable results. Anyway here's a prediction: subsequently all graphic operations will fail, you window will start displaying graphics "borrowed" from the overlapping windows.

  8. #8
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Repaint failure

    Thanks for your ideas.
    Quote Originally Posted by srelu View Post
    1. You forget to deselect the hBitmap from the dc at the end. That will create problems for sure.
    Forget? No. What is "deselect"? There is no other bitmap existing to "replace" the one containing the window's image. Are you saying I should have a "null" bitmap handle to replace hBm when painting is done?
    2. The fact that WM_PAINT is sent doesn't mean necessarily that it will repaint the whole window. It will repaint only the invalid region of the window. You don't need to bother about that, the OS will properly invalidate any area in need to be repainted.
    Yes, I know this.
    a. Are you sure the right bitmap is selected all the time in the sdc ?
    b. Is the bitmap containing the right image ?
    c. Are coordinates and sizes properly calculated ?
    d. Is your bitmap large enough to cover the whole window ?
    a) Yes, there is only one.
    b) Absolutely.
    c) Yes.
    d) Yes.
    4. Never call Invalidate from the inside of the WM_PAINT message handler.
    I have never done this before, but out of desperation, I had to try different things. This seemed to eliminate the ghost trails (in trade for intermittent flickering).
    5. Are you sure that you comply with all the requirements to deal with graphic functions ?
    AFAIK.
    - Each SelectObject must have a pair that deselects that object when no longer needed
    I have never heard if this in 15 years of GDI programming. I wonder why not.
    - Each bitmap creation function must have a DeleteObject pair to delete it when no longer needed
    - Each dc created must be deleted/released when no longer necessary.
    DC function pairs:
    BeginPaint with EndPaint
    GetDC with ReleaseDC
    CreateCompatibleDC with DeleteDC
    Understood. I always do this. I typically use NuMega Bounds Checker to tell me if I am missing any DeleteXX calls.
    When deleting a dc, none of the objects created by you must be left selected in it. (That's what you did wrong here. And probably there are more in the code you didn't post.)
    Again, I have never heard of this. Do you have a link to info that says this is so?
    Failure to comply with all these requirements will lead to serious problems. Just creating graphic objects and not disposing them properly will fill all the GDI memory with useles objects. You will run out of the GDI memory with unpredictable results. Anyway here's a prediction: subsequently all graphic operations will fail, you window will start displaying graphics "borrowed" from the overlapping windows.
    I have never had any GDI problems in many years of intermittent Windows programming. This is the first instance of "repaint failure", and it is curious that it happens only on XT and sometimes on Vista, but never on W2K. I do not have Win7 to test on.

    I will try some of your ideas, only because I have nothing to lose. If they magically fix my problem, then I will return here to eat crow.
    Last edited by cosmicvoid; April 19th, 2010 at 06:54 PM.

  9. #9
    Join Date
    Aug 2000
    Location
    New York, NY, USA
    Posts
    5,656

    Re: Repaint failure

    Quote Originally Posted by cosmicvoid View Post
    I have never heard if this in 15 years of GDI programming. I wonder why not.
    That's strange. Check out MSDN:
    An application should always replace a new object with the original, default object after it has finished drawing with the new object.

    Some versions of Windows are more forgiving than others, and not all GDI objects cause the same damage.
    You just might have a longest streak of luck.
    Vlad - MS MVP [2007 - 2012] - www.FeinSoftware.com
    Convenience and productivity tools for Microsoft Visual Studio:
    FeinWindows - replacement windows manager for Visual Studio, and more...

  10. #10
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Repaint failure

    The very first hit: SelectObject. And you have your warning alright:
    Remarks

    This function returns the previously selected object of the specified type. An application should always replace a new object with the original, default object after it has finished drawing with the new object.
    Quote Originally Posted by VladimirF
    Some versions of Windows are more forgiving than others..
    ..or rather current complexity just exceeded tolerance threshold
    Best regards,
    Igor

  11. #11
    Join Date
    Apr 2009
    Posts
    598

    Re: Repaint failure

    I had the same problems, with a different program where I always carefully replace and deselect objects that I use, consciously following the basic guidance of Charles Petzold. So the problem is not caused by any resources that are not rightly freed or released.

    The problem I noticed occurs when there is a scrollbar, and I see that cosmicvoid must also have a srcollbar, since he uses si.nPos. I believe the problem is a bug in some versions of Windows, because the window is supposed to be unchanged, when it actually is, and this would be the reason the extra unvalidateRect() is working, because it is placing a message in the queue forcing a repaint. But it seems the problem does not exist anymore with Windows 7.

  12. #12
    Join Date
    Apr 2010
    Location
    Western WA, USA
    Posts
    59

    Re: Repaint failure

    Well, I see that I am proven wrong about the GDIOBJECT select/deselect, and I admit my mistake . I guess that's what happens when you keep re-using chunks of programs that were developed on Win98 .

    So, after adding a lot of lines of code to "pair up" the object select and restore, I am disappointed to report that the program behavior is exactly the same: it is trouble free on Win2K, flickers slightly on Vista, and flickers/ghost trails badly on XP.

    @olivthill2: Yes, there is a scroll bar sometimes, depending on the user's screen size vs the size of the image. It makes no difference whether the scroll bar is in use or not.

    So those changes are not the magic bullet , and I am still hoping for ideas to try.
    Last edited by cosmicvoid; April 20th, 2010 at 06:55 AM.

  13. #13
    Join Date
    Nov 2000
    Location
    Voronezh, Russia
    Posts
    6,620

    Re: Repaint failure

    First of all you are to find out when the problem occurs: just dump your buffered image to file and see if it gets spoiled before blitting. If it doesn't, try to play with display settings (it might be display driver problem), etc.
    Best regards,
    Igor

  14. #14
    Join Date
    May 2002
    Location
    Lindenhurst, NY
    Posts
    867

    Re: Repaint failure

    If you post an SSCCE you may get better help and/or an actual solution or fix (time won't be wasted on guessing).

  15. #15
    Join Date
    Feb 2005
    Posts
    2,160

    Re: Repaint failure

    What is sdc and where is it configured? Have you tried blitting the entire bitmap to the entire client area instead of just the clip box portion? You may be calculating the dimensions and/or offset incorrectly.

Page 1 of 2 12 LastLast

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured