Discussion:
CPaintDC Memory Leak
(too old to reply)
davidm
2006-03-15 13:04:52 UTC
Permalink
Hi,

I'm battling to find the cause of a memory leak in one of my evc++
dlls.

The dll creates a window, and draws to it in response to a WM_PAINT
message (as usual).

The trouble is that I've removed all the code from the OnPaint method
except the following:
void CMapWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
}

which still causes the leak.

Removing the CPaintDC line removes the leak.

Any thoughts on what could be going wrong here? I'm at my wits end.

Thanks,

Dave.
David Moss
2006-03-16 09:17:10 UTC
Permalink
As an update, I tried replacing the CPaintDC with CClientDC to see what
happens and noticed 2 things:
- the window decorations (Scroll bars and Toolbar) were no longer
drawn.
- the memory leak did not appear.

Any insights or thoughts would be greatly appreciated.

Dave.
Voidcoder
2006-03-16 10:16:23 UTC
Permalink
How much (bytes) leaks per call? Does it happen on any call?
You may want to debug the ~CPaintDC() destructor, it seems the
only place for the leak to occur is when the HDC handle is not
found/removed from the global GDIOBJ map in the Detach()
method.
Post by David Moss
As an update, I tried replacing the CPaintDC with CClientDC to see what
- the window decorations (Scroll bars and Toolbar) were no longer
drawn.
- the memory leak did not appear.
Any insights or thoughts would be greatly appreciated.
Dave.
David Moss
2006-03-16 14:01:44 UTC
Permalink
Thanks for the replies.
The leak is almost always 32 bytes, and occasionally 96 (2x48?). Not a
massive amount I know, but it is lost every time the OnPaint method is
drawn for my window. In an application where the screen is updated
regularly, you soon notice the leak.

Why do you think replacing CPaintDC with CClientDC prevents the window
scroll bars (and parent window toolbar) from being drawn? Could there
be a problem with resources for scroll bars?
Voidcoder
2006-03-16 14:31:35 UTC
Permalink
CPaintDC wraps the BeginPaint() / EndPaint() API
and normally is used while processing the
WM_PAINT message.

CClientDC wraps the GetDC() / ReleaseDC() API
and can be used in any place to access the client
area context.


Try to replace

CPaintDC(this)

with

PAINTSTRUCT ps;
BeginPaint(m_hWnd, &ps);
EndPaint(m_hWnd, &ps);

and see if the problem is still there.
Post by David Moss
Thanks for the replies.
The leak is almost always 32 bytes, and occasionally 96 (2x48?). Not a
massive amount I know, but it is lost every time the OnPaint method is
drawn for my window. In an application where the screen is updated
regularly, you soon notice the leak.
Why do you think replacing CPaintDC with CClientDC prevents the window
scroll bars (and parent window toolbar) from being drawn? Could there
be a problem with resources for scroll bars?
David Moss
2006-03-16 15:18:25 UTC
Permalink
I tried

void CMapWnd::OnPaint()
{
PAINTSTRUCT ps;
::BeginPaint(m_hWnd, &ps);
EndPaint(m_hWnd, &ps);
}

and the leaks were still there.

I also tried removing my implementation of OnPaint completely, so that
the default CWnd::OnPaint would be called, but the leak was still
there.

Interestingly, I tried

void CMapWnd::OnPaint()
{
}

and the leaks got worse.

I'm at a bit of a loss here. The problem was initially noticed when
switching between the main app window and another - the memory usage
would slowly creap up. I was drawing several points on the screen and
was convinced that it would be something to do with my code responsible
for drawing to CMapWnd, but having gone through all of that and now
disabled it all entirely I'm still getting the leak.
voidcoder
2006-03-16 19:55:52 UTC
Permalink
Hm, that makes sense. At least we know the problem is
not connected with the CPaintDC itself.

Well, are you handling also WM_ERASEBKGND
message? Note when you call BeginPaint and the
dirty rect is marked to be erased, you will get
also WM_ERASEBKGND message. So if you
have any code inside the OnEraseBkgnd()
comment it out to be sure.
Post by David Moss
I tried
void CMapWnd::OnPaint()
{
PAINTSTRUCT ps;
::BeginPaint(m_hWnd, &ps);
EndPaint(m_hWnd, &ps);
}
and the leaks were still there.
I also tried removing my implementation of OnPaint completely, so that
the default CWnd::OnPaint would be called, but the leak was still
there.
Interestingly, I tried
void CMapWnd::OnPaint()
{
}
and the leaks got worse.
I'm at a bit of a loss here. The problem was initially noticed when
switching between the main app window and another - the memory usage
would slowly creap up. I was drawing several points on the screen and
was convinced that it would be something to do with my code responsible
for drawing to CMapWnd, but having gone through all of that and now
disabled it all entirely I'm still getting the leak.
David Moss
2006-03-17 09:37:53 UTC
Permalink
Well, I think that's done it!

My implementation was as follows:

BOOL CMapWnd::OnEraseBkgnd(CDC* pDC)
{
/* [some disabled code] */
return CWnd::OnEraseBkgnd(pDC);
}

As I understand it this should have behaved as though this method
wasn't there, defaulting to the CWnd implementation. However, after
commenting this method completely and removing from the message map
declarations at the top the leak has disappeared.

I'd be interested to know why the above didn't work correcly, but as
the leak has now gone I'm happy. :-)

Thank very much for all the help.

Dave.

Ulrich Eckhardt
2006-03-16 10:40:40 UTC
Permalink
Post by davidm
The trouble is that I've removed all the code from the OnPaint method
void CMapWnd::OnPaint()
{
CPaintDC dc(this); // device context for painting
}
which still causes the leak.
Reduce it further. Debug into the ctor and dtor, and replace those by the
win32 API calls (BeginPaint, EndPaint) they do to find out what exactly
causes the problem.

Uli
Loading...