Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Using MessageBox in a WM_PAINT procedure

Status
Not open for further replies.

LyMc

Programmer
Jun 3, 2003
84
US
I have a Windows SDK program that runs an extensive WM_PAINT routine to generate the window contents. I would like to be able to use MessageBox to display an error while drawing the window, but it seems that the act of putting up the MessageBox causes another WM_PAINT message to be issued, which encounters the error again, which tries to put up a MesssageBox, etc, etc until the stack overflows.

I can understand why a WM_PAINT may get generated when the Message Box is torn down, but why when it is put up? Since I can't find a similar problem reported I'd assume I'm doing something wrong.
 
You can't use MessageBox to display an error in WM_PAINT since, as you found out it causes infinite redraws.

Option 1: post a message and return from WM_PAINT. The posted message can use a MessageBox.

Option 2: do not overlap VS and your application: that way there will be fewer redraws. Use __asm int 3 to stop the program so you can see where the error is (unless you're using that dreaded Microsoft invention called managed code). I've got no idea whatsoever if you're using managed code.

Option 3: remote debugging - attach to the process from a different PC. That way there are no overlaps, changes of focus etc. Great but not everyone has this luxury. You can always borrow a collegues machine after hours.
 
xwb, thanks for the response. I'll consider doing option 1.

If I understand you correctly, option 2 is telling me that what is causing the redrawing to happen repeatedly is the fact that I'm trying to debug on the same machine I'm running the app on. I'm not actually using the MessageBox to debug; it's use is functional, warning the app's user that there is something missing in the data input, therefore option 1 seems like the proper way to go. I'm not concerned about additional redraws while debugging, so if that is what is causing it, then I'll use option 1 to fix it, and that's cool.

As I said, I'm running pure SDK - no MFC, no managed, no .NET. - right out of Petzold. I'm a C coder from way back and am loathe to give up my old ways. I'm doing classes and object-oriented (with, of course, a few "get arounds" to handle the message handling).

Thanks for the help.
 
WM_PAINT is intended to be a relatively low-level thing - drawing, not calculating and not resizing the window and not allowing menu choices to be made... (it only even gets called when there is absolutely nothing else to do). you should definitely be doing nothing but painting there. After all, there can really be no true error (as such) in drawing - the error is in calculations related to the drawing. The code responsible for discovering that error should be the one reporting it, with WM_PAINT just doing the best it can with the data given to it.
 
Well, the best way to display errors out of WM_PAINT is to post a timer message (using SetTimer with an interval of 100 milliseconds or so) and then process it in WM_TIMER. This way your painting operation will end and you'll display your message after that, thus not having any visual distortions of your program.

There's also one thing you have to remember here -- you need some synchronization before running SetTimer, as otherwise you'll have the same problem with many message boxes popping up. You can use Windows synchronization functions, but better use simple static variable:

Code:
#define ID_MY_WM_PAINT_TIMERID 0x2005
static BOOL bOnceShown = FALSE;
...
case WM_PAINT:
{
    //Your painting part here
    ...

    if(error)
        if(!bOnceShown)
        {
            bOnceShown = TRUE;
            SetTimer(hWnd, ID_MY_WM_PAINT_TIMERID, 100, NULL);
        }
}
break;
....

case WM_TIMER:
{
    if(wParam == ID_MY_WM_PAINT_TIMERID)
    {
        //Kill timer
        KillTimer(hWnd, wParam);

        //Show your message box here

        //Restore flag
        bOnceShown = FALSE;
    }
}
break;
}

There's one "but" though... Make sure your users don't have the same error popping up every second -- it might be very annoying, so you'll have to modify this little sample above. It'd be also 100 times better if you analyze your data and display errors before you start painting client area -- just a suggestion.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top