Home > Software engineering >  Does calling GetDC directly create memory leaks?
Does calling GetDC directly create memory leaks?

Time:10-13

I am listening to the ON_WM_ERASEBKGND() msg, inside the fired function relative to that event called OnEraseBackground(CDC* pDC). I am changing a background color like the following:

if (pDC)
{
    pDC->SetBkColor(BlackColor);        
}
else if (GetDC())
{
    GetDC()->SetBkColor(BlackColor);            
}

My question is, should I call ReleaseDC() after GetDC()?

CodePudding user response:

A device context returned from GetDC or CWnd::GetDC should always be released by passing it either to ReleaseDC or CWnd::ReleaseDC (doesn't matter which one). The documentation is a fair bit lenient towards situations where this isn't strictly necessary, though establishing those preconditions is complex in itself.

If you call either of the ReleaseDC functions on a device context that doesn't strictly need to be released, the operation has no adverse effect.

The consequences of not releasing device contexts (a GDI resource) is far worse than a memory leak. GDI resources are severely limited, and shared across all processes running in the same user session. One program's GDI resource leak can easily cause any other program to malfunction.

Note that you are calling GetDC twice in your code so you will want to release it twice as well. Alternatively, only call it once, e.g.

if (pDC)
{
    pDC->SetBkColor(BlackColor);        
}
else
{
    auto myDC = GetDC();
    myDC->SetBkColor(BlackColor);
    ReleaseDC(myDC);
}

or, using an if statement with initializer (introduced in C 17):

if (pDC)
{
    pDC->SetBkColor(BlackColor);        
}
else if (auto myDC = GetDC())
{
    myDC->SetBkColor(BlackColor);
    ReleaseDC(myDC);
}

Though, really, I would probably just scrap the entire else-arm. If your WM_ERASEBKGND message handler doesn't receive a device context, then there's no reason to go hunting for one yourself.

CodePudding user response:

Win32 API

According to this article for GetDC it states:

After painting with a common DC, the ReleaseDC function must be called to release the DC. Class and private DCs do not have to be released. ReleaseDC must be called from the same thread that called GetDC. The number of DCs is limited only by available memory.


CWnd

If it is a CWnd::GetDC then:

Unless the device context belongs to a window class, the ReleaseDC member function must be called to release the context after painting.


Under normal circumstances you would do this:

CDC *pDC = GetDC();
if (pDC != nullptr)
{
   pDC->SomeFunc(...);
}
// etc..

The linked article refers to some samples here.

Does that help?

  • Related