Hi There, I am creating a Windows C++ program.
It is one of my first so I'm trying to keep it simple.
I am creating a simple maze game and using coloured rectangles to represent the player and other obstacles. The coding is coming along nicely but I am having a problem with the colours disappearing after a while of the game being played. All colours leave the screen and only the the white filled rectangles with single line black boarders remain. The colours work as they should when I restart the program.
It is almost as if I am rendering the screen too much and it just gives up!
It happens at a seemingly random time as well.
Can anyone tell me what is going on? Is it something that I can fix?
I'm betting that you are incorrectly managing the window DC. It almost sounds like you are getting it, but never releasing it.
Remember that each call to GetDC must have a matching call to ReleaseDC. Every BeginPaint must have a matching EndPaint, etc.
Additionally, you want to "get" the screen DC for the shortest time possible. That is... get it, quickly do your drawing, then release it ASAP. You don't want to mess around doing other things while you have the DC locked.
If you keep the DC for extended periods, it screws up other parts of Windows that tries to manage it, since it's also trying to get it but it can't because your program has it. This can result in very strange behavior like what you're seeing.
But this is all a total guess. I might be way off base. It would really help if you could post you drawing code.
Ok that makes sense but I cannot find any non balanced getDC or Begin Paint calls, perhaps it is because I have so much code in the WM_PAINT case? Here is my basic code ommitting the tonnes of drawing code.
When I change the maze.memhdc = BeginPaint(hWnd, &ps); to maze.hdc = BeginPaint(hWnd,&ps);
the window is blank unless I add maze.memhdc = GetDC(hWnd); after it after all I am only drawing to the offscreen dc then copying it across to the screen dc using BitBlt...
this still did not solve the problem though :(
Obviously when I added GetDC at the top I also added RemoveDC just before EndPaint.
Have you got any more ideas?
Oh and I got rid of the DeleteDC on line 18 - thanks for pointing that out!
What Disch is saying is that it is not logical to assign the BeginPaint()'s HDC to maze.memhdc. For starters, this will make you leak the compatible DC that you create in WM_CREATE.
In general, your painting procedure needs to go like this:
1. Call BeginPaint(). Store the HDC in maze.hdc.
2. Run your drawing routines against the compatible DC in maze.memhdc.
3. Blit the mem DC into maze.hdc.
4. Call EndPaint().
If you are doing this, you are losing your offscreen memory DC (memory leak) and replacing the handle with the screen DC (which will eventually become defunct because it becomes invalid as soon as you EndPaint).
This is certainly the cause of your problems. If changing that to maze.hdc does not fix it, then it must be because you are mixing up hdc and memhdc elsewhere in your code.
To fix... start by getting rid of maze.hdc entirely. You don't need that to be a member of any kind of longterm struct. You need the screen DC for exactly 3 lines of code (BeginPaint, BitBlt, EndPaint).
Instead, the screen DC would be local to the drawing function (your WM_PAINT handler).
It should look like this:
1 2 3 4 5 6 7 8
case WM_PAINT:
// do all your drawing to maze.memhdc here
// no need to GetDC or any of that garbage -- just do the drawing.
HDC screendc = BeginPaint( wnd, &ps );
BitBlt( ... /* blit maze.memhdc to screendc here */ ... );
EndPaint( wnd, &ps );
break;
If there's no GetDC, there shouldn't be a ReleaseDC. You are not using GetDC here.
As for the flickering, webJose's solution will work (give NULL for the window's background brush). Another approach is to handle the WM_ERASEBACKGROUND message and have it do nothing (return 0 instead of calling DefWindowProc). Both should have the same effect, although webJose's approach is probably cleaner and more to the point.
Brilliant - all flickering is gone! That is exactly what I hoped for when I decided to use a double buffer, Thanks for that tip guys!
As for the freezing, still happening but I will try to look into it more and become more familiar with those functions
Thank you very much for both of your help! I definatley feel like I have learned a lot about the subject in the past few days, I will probably post on this thread then mark it as solved if I manage to find and fix the problem!
If the problem is a GDI object overflow you can diagnose it easy enough with the window task manager. In the processes tab enable the GDI Objects column then observe that value while your program runs. If it never stables out but keeps increasing then there's a problem.
It now works - I brought up taskmanager and found that the app was increasing by 18 GDI objects everytime the WM_PAINT was loaded it capped at 10,000 which is when the screen stopped. I then realised that I was creating lots of new pens and brushes and put in
1 2
DeleteObject(pen);
DeleteObject(brush);
After each was used! It now jumps straight to 30 GDI objects wavers between 29 and 30 for some reason, but it does not increase anymore!