DQQpy DQQpy - 3 months ago 16
C Question

WinAPI managing brushes

I don't get how I am supposed to handle brushes for coloring static text background.
At first everything looks nice as it is supposed to be:

enter image description here

However, after the statics have been redrawn for several times, they change to this:

enter image description here

I also noticed this depends on whether I'm straight returning the same brush in every case (for debugging) or using the actual code with different cases(grey boxes after first redrawing).

My

WM_CTLCOLORSTATIC
message handling looks like this:

case WM_CTLCOLORSTATIC:
{
HDC hdcStatic = (HDC) wParam;
SetTextColor(hdcStatic, RGB(0,0,0));
HBRUSH hbrDefault = CreateSolidBrush(RGB(255,255,255));
return (INT_PTR)hbrDefault;


(Simplified for debugging)

I guess this has something to do with freeing the brushes after using with
DeleteObject()
, but how could I do this when I need to return the brushes, but I want to delete them before leaving the function?
MSDN resources didn't help:
WM_CTLCOLORSTATIC


EDIT : I found my mistake.



I declared my brushes as global variables like this:

HBRUSH hbrBkFoodCat[FOODCAT_LENGTH];
HBRUSH hbrDefault;


But then I initialised them on startup like this:

for(int i=0;i<FOODCAT_LENGTH;i++) {
hbrBkFoodCat[i] = CreateSolidBrush(foodCatClr[i]);
}
HBRUSH hbrDefault = CreateSolidBrush(RGB(255,255,255));


As you can see, I accidentally declared
hbrDefault
again but this time as a local variable, so at message handling I got that grey boxes (NULL brush).
What I tried out (stupid idea I know), was to initialize them at message handling. Since I just copy-pasted that initialization right into the handling, it became a local variable again, but this time it was 'in range' for the return. This lead me to the assumption something was wrong with freeing the brushes, because of having to redraw it numerous times before getting that grey background (still don't get this though).

Thank you all for your help anyway!

Answer

Do not create a new brush every time you process a WM_CTLCOLORSTATIC message. That is a resource leak. Create the brush one time, either when you first create the static text control, or when it sends you WM_CTLCOLORSTATIC for the first time. Keep returning that same brush for every WM_CTLCOLORSTATIC message:

HBRUSH hbrStaticBkg = NULL;

...

case WM_CTLCOLORSTATIC:
{
    HDC hdc = (HDC) wParam;
    SetTextColor(hdc, RGB(...));
    if (!hbrStaticBkg) hbrStaticBkg = CreateSolidBrush(RGB(...));
    return (LRESULT) hbrStaticBkg;
}

Destroy the brush only after you have destroyed the static text control.

DestroyWindow(hwndStatic);
if (hbrStaticBkg) {
    DeleteObject(hbrStaticBkg);
    hbrStaticBkg = NULL;
}

If you want to change the background color during the lifetime of the static text control, destroy the brush and invalidate the control to trigger a repaint, then create the new brush when requested.

COLOREREF clrStaticText = RGB(0,0,0);
COLORREF clrStaticBkg = RGB(255,255,255);
HBRUSH hbrStaticBkg = NULL;

...

case WM_CTLCOLORSTATIC:
{
    HDC hdc = (HDC) wParam;
    SetTextColor(hdc, clrStaticText);
    if (!hbrStaticBkg) hbrStaticBkg = CreateSolidBrush(clrStaticBkg);
    return (LRESULT) hbrStaticBkg;
}

...

clrStaticText = RGB(...);
clrStaticBkg = RGB(...);
if (hbrStaticBkg) {
    DeleteObject(hbrStaticBkg);
    hbrStaticBkg = NULL;
}
InvalidateRect(hwndStatic, NULL, TRUE);
Comments