Solved

Problems with WM_ERASEBKGND in DialogBox

Posted on 2004-10-06
10
1,441 Views
Last Modified: 2013-12-03
First up: I am not using MFC, I am using plain a old Win32 DialogBox(...).

I read an article saying I could create a gradient background by handling the WM_ERASEBKGND message in my dialogue's message proc.  I've done that and it looks good but the problem is as soon as I move my dialogue everything goes bad.  Other controls don't repaint properly if at all and if move the dialogue so that any part of it leaves the viewport then I get artifacts everywhere (everywhere on my moniter, not just the dialog).

Prior to this I didn't overload WM_ERASEBKGND, instead I just returned a solid brush from WM_CTLCOLORDLG and everything was happy (though boring).  What am I doing wrong?

Here is a truncated version of my msg proc:
<cpp>
INT_PTR CShell::MsgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
{
    switch(msg)
    {    
        case WM_ERASEBKGND:
        {
            //if(HDC(wParam) != GetDC(Instance()->hWnd)) return FALSE;
            //doesn't work

            RECT rect, row;
            BYTE r, g, b;
            GetClientRect(hDlg, &rect);
            row.left = 0;
            row.right = rect.right;
           
            //--- loop through 1 pixel high rows ---//
            for(int i = 0; i < rect.bottom; ++i)
            {
                r = static_cast<BYTE>(r1 + (i * (r2-r1) / rect.bottom));
                g = static_cast<BYTE>(g1 + (i * (g2-g1) / rect.bottom));
                b = static_cast<BYTE>(b1 + (i * (b2-b1) / rect.bottom));

                row.top = i;
                row.bottom = i+1;
                FillRect(reinterpret_cast<HDC>(wParam), &row, CreateSolidBrush(RGB(r, g, b)));
            }


            return TRUE;
        }
    }
    return FALSE;
}</cpp>
0
Comment
Question by:skirmish76
  • 5
  • 5
10 Comments
 
LVL 11

Expert Comment

by:KurtVon
ID: 12238074
Hmm, works for me.  The only problem I can see is that you are leaking GDI handles like crazy.  Maybe your system is just running out when you are testing?

Change the FillRect line to

HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
FillRect(reinterpret_cast<HDC>(wParam), &row, hBrush);
DeleteObject(hBrush);

and that should solve the leak.

Hope this helps.
0
 

Author Comment

by:skirmish76
ID: 12239293
Thanks for the reply Kurt.  I added the clean up you suggest but the problem remains.  Still now at least it is bleeding the GDI dry.

Cheers
-A-
0
 
LVL 11

Expert Comment

by:KurtVon
ID: 12240077
Hmm, like I said, it works fine on my machine.

Did you override WM_PAINT also?  I left all messages except the WM_ERASEBKGND blank.
0
 
LVL 11

Expert Comment

by:KurtVon
ID: 12241725
What I'd suggest is try commenting out all dialog functionality except the creation needed code and the WM_ERASEBKGND handler.  Just the minimum code to keep the program from crashing.  Then test it again and see if the drawing problem still happens.  If it doesn't, then add back in the code until it starts again.

If it does still happen try replacing your drawing code with a simple PatBlt and see if it still causes trouble.  If not, it's part of the drawing code, maybe something still isn't being freed correctly.

If it does still happen, try commenting out the WM_ERASEBKGND message handler entirely.  If it doesn't happen (and the dialog should look pretty odd in this case, always showing what was under it before it moved)  try explicityly casting the parameter just once.

Hope this helps.
0
 

Author Comment

by:skirmish76
ID: 12245845
I commented out all the other messages and I still have the problem.  I suspected that maybe several WM_ERASEBKGND messages were being sent before the first had completed but I checked for that and it is fine.

I can put as much code in that message as I like and it fine, the one line causing all the problems is:
FillRect(reinterpret_cast<HDC>(wParam), &row, CreateSolidBrush(RGB(r, g, b)));

If I comment it out then the app is fine (of course it has no background).

The redraw is painfully slow (you can see the trace across the dialog) when it is stationary but when I move the dialog so any of it goes outside of screen space or another app gets focus then it completely flakes out - components just aren't redrawn fully and vertical stripes appear on the entire screen.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 

Author Comment

by:skirmish76
ID: 12246460
I replaced the FillRect with a PatBlt and the problem remains, however it is now only evident if I move the window so it leaves the screen or move another window on top of it.  

If I alt+tab from the app and then back to it though it does repaint properly.

By handling the WM_ERASEBKGND  message for my dialogue it seems to screw with the repainting of other components (or maybe it is painting over them).
0
 
LVL 11

Expert Comment

by:KurtVon
ID: 12248539
You did change the line to

FillRect(reinterpret_cast<HDC>(wParam), &row, hBrush);

right?  You see, the call CreateSolidBrush uses up one GDI resource, and if you don't hold onto the handle it returns in a variable, then it is impossible to delete the object.  Creating too many GDI handles without deleting them will slow down, and eventually halt, all graphics operations.  That's what was causing the leak before.

Changing it to a PatBlt still caused problems, but only with the redraw?  Does the inner loop now look like

        r = static_cast<BYTE>(r1 + (i * (r2-r1) / rect.bottom));
        g = static_cast<BYTE>(g1 + (i * (g2-g1) / rect.bottom));
        b = static_cast<BYTE>(b1 + (i * (b2-b1) / rect.bottom));

        row.top = i;
        row.bottom = i+1;
        /*
        HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
        FillRect(reinterpret_cast<HDC>(wParam), &row, hBrush);
        DeleteObject(hBrush);
        */
        PatBlt(reinterpret_cast<HDC>(wParam), row.left, row.top, row.right - row.left, 1, WHITENESS);

because I'm not getting any drawing problems this way either.
0
 

Author Comment

by:skirmish76
ID: 12248738
Yep I deleted the brush as you suggested.  To be honest my initial code style is slap it together and if it works then clean it up.  I should probably get in the habit of cleaning as I go.  Here is my unabridged code with the PatBlt and the FillRect commented out:

<code>
case WM_ERASEBKGND:
{
    RECT rect, row;
    BYTE r, g, b, r1, g1, b1, r2, g2, b2;
    GetClientRect(hDlg, &rect);
    row.left = 0;
    row.right = rect.right;
   
    //--- extract clr elements ---//
    r1 = static_cast<BYTE>((Instance()->clrTop & 255 << 16) >> 16);
    g1 = static_cast<BYTE>((Instance()->clrTop & 255 << 8)  >> 8);
    b1 = static_cast<BYTE>(Instance()->clrTop & 255);
    r2 = static_cast<BYTE>((Instance()->clrBtm & 255 << 16) >> 16);
    g2 = static_cast<BYTE>((Instance()->clrBtm & 255 << 8)  >> 8);
    b2 = static_cast<BYTE>(Instance()->clrBtm & 255);

    //--- loop through 1 pixel high rows ---//
    for(int i = 0; i < rect.right; ++i)
    {
        r = static_cast<BYTE>(r1 + (i * (r2-r1) / rect.right));
        g = static_cast<BYTE>(g1 + (i * (g2-g1) / rect.right));
        b = static_cast<BYTE>(b1 + (i * (b2-b1) / rect.right));

        row.top = 0;
        row.bottom = rect.bottom;
        row.left = i;
        row.right = i+1;

        //FillRect Method
        //HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
        //FillRect(GetDC(Instance()->hWnd), &row, hBrush);
        //DeleteObject(hBrush);
       
        HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
        SelectObject(Instance()->hDC, hBrush);
        PatBlt(Instance()->hDC, i, 0, 1, rect.bottom, PATCOPY);
        DeleteObject(hBrush);
    }

    return TRUE;
}
</code>

I can't figure out what is going, I am running some pretty processor and gpu intensive stuff in this app and then I change the background render and kaput!  I should learn from my mistakes, don't try to be too smart.

Cheers
-A-
0
 
LVL 11

Accepted Solution

by:
KurtVon earned 275 total points
ID: 12248873
Ah, I see the problem with the PatBlt code.  When you select an object into a DC, you must select the old object back in before delting it.  So change that section to

        HBRUSH hBrush = CreateSolidBrush(RGB(r, g, b));
        HGDIOBJ hOldBrush = SelectObject(Instance()->hDC, hBrush);
        PatBlt(Instance()->hDC, i, 0, 1, rect.bottom, PATCOPY);
        SelectObject(Instance()->hDC, hOldBrush);
        DeleteObject(hBrush);

I'm also not clear why the Instance()->hDC is used.  You must never hold on to a DC across messages for any reason -- Windows recycles them for use with other controls so they have a good chance of not being valid on the next message.  WM_ERASEBKGND always passes the current HDC as the wParam.  You can save soome headaches by assigning it to a local variable within the call, for convenience, but in the call, only draw to that DC.
0
 

Author Comment

by:skirmish76
ID: 12249049
Kurt you are a champion, that worked a treat.  Thanks for your continued help with this problem, I guess it is pretty clear I am a GDI newbie.  While on the topic I have another question about GDI if you fancy the points:  http://www.experts-exchange.com/Programming/Programming_Platforms/Win_Prog/Q_21158212.html

Thanks again mate.
Adam
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
Windows Drag & Drop Location 2 94
Problem to packaging 1 83
Messagebox for a Web Site Application 4 63
How do ASP.NET and MVC work together? 4 29
If you have ever found yourself doing a repetitive action with the mouse and keyboard, and if you have even a little programming experience, there is a good chance that you can use a text editor to whip together a sort of macro to automate the proce…
In this article, I will show how to use the Ribbon IDs Tool Window to assign the built-in Office icons to a ribbon button.  This tool will help us to find the OfficeImageId that corresponds to our desired built-in Office icon. The tool is part of…
This is Part 3 in a 3-part series on Experts Exchange to discuss error handling in VBA code written for Excel. Part 1 of this series discussed basic error handling code using VBA. http://www.experts-exchange.com/videos/1478/Excel-Error-Handlin…
Migrating to Microsoft Office 365 is becoming increasingly popular for organizations both large and small. If you have made the leap to Microsoft’s cloud platform, you know that you will need to create a corporate email signature for your Office 365…

867 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now