Click here to Skip to main content
Licence 
First Posted 9 Nov 2000
Views 169,261
Bookmarked 45 times

A thread-safe timed message box

By | 12 Feb 2001 | Article
The system Message Box that is closed atuomatically after some time

What is the code for

This is for using the systems MessageBox (no extra dialog creation needed). After a time with no user-response the dialog is automatically closed. An optional text showing the time left to interact is provided. It's also a replacement for MSDN Q181934 (doesn't work)

Basics

Before calling MessageBox, a timer is installed. In the timer's callback-procedure the message-text from the box is replaced (optional).

When the box should be closed, a WM_COMMAND is posted to the MessageBox Window.

Timer-Callback

I decided to collect all the information corresponding to the MessageBox (title, Message, Flags ...) in a class. Then there is the problem that only a static timer-callback-procedure can be installed with the SetTimer()-function: one can not access the class-members (as it is static).

To solve this problem, I inserted a Map to store the classes corresponding to a timer-id:

Header:

class CDlgTimedMessageBox
{
public:
    // ...
    UINT         ShowMessageBox(BOOL *pbStoppedByUser=NULL);
    // ...
    static void  CALLBACK GlobalTimerProc(HWND hwnd, UINT uiMsg, 
                                          UINT idEvent, DWORD dwTime);
    void         LocalTimerProc(void);
    // ...
    static       CMapPtrToPtr        m_mapTimerIdToClassMe;

    // to call the messagebox within one line !
    static UINT  TimedMessageBox(...);

protected:
    UINT         m_idTimer;
};

Source:

UINT CDlgTimedMessageBox::ShowMessageBox(BOOL *pbStoppedByUser)
{
    // ...
    m_idTimer = ::SetTimer(NULL, 0, 1000, 
                    (TIMERPROC) CDlgTimedMessageBox::GlobalTimerProc);
    CDlgTimedMessageBox::m_mapTimerIdToClassMe.SetAt((void*)m_idTimer, 
                                                     this);
    // ...
    ::MessageBox(...)
    // ...
}

void CALLBACK CDlgTimedMessageBox::GlobalTimerProc(HWND hwnd, 
                               UINT uiMsg, UINT idEvent, DWORD dwTime)
{
    CDlgTimedMessageBox    *pMe = NULL;
    
    // Find the corresponding class by the timer-id
    CDlgTimedMessageBox::m_mapTimerIdToClassMe.Lookup((void*)idEvent, 
                                                       (void *&) pMe);
    
    if( pMe!=NULL )
        pMe->LocalTimerProc();
}

void CDlgTimedMessageBox::LocalTimerProc(void)
{
    // find the Message-Box-window

    // Calculate time since start
    
    if( too long running )
    {
        // Stop MessageBox
    }
    else
    {
        // replace text of MessageBox    
    }    
}

Finding the MessageBox

hWnd = ::GetWindow(::GetDesktopWindow(), GW_CHILD);
while( (hWnd!=NULL) && (m_hMsgBox==NULL) )
{
    pWnd = CWnd::FromHandle(hWnd);
    pWnd->GetWindowText(title);

    if( AfxIsDescendant(m_hParent, hWnd) && ::IsWindowVisible(hWnd) && 
        (m_Title.CompareNoCase(title)==0) )
    {
        m_hMsgBox = hWnd;
        break;
    }
    
    hWnd = ::GetWindow(hWnd, GW_HWNDNEXT);
}

 

Put it in one function

There is one function you can use to call the messagebox without creating a class-instance: CDlgTimedMessageBox::TimedMessageBox() does the rest for you!

UINT CDlgTimedMessageBox::TimedMessageBox(UINT flags, LPCTSTR ptszMessage, 
                          LPCTSTR ptszTitle, 
                          DWORD dwTimeout, UINT dDefaultReturn,
                          LPCTSTR ptszMessageTimer, HWND hwndParent, 
                          BOOL *pbStoppedByUser)
{
    CDlgTimedMessageBox    msgBox(flags, ptszMessage, ptszTitle, 
                                  dwTimeout, dDefaultReturn, 
                                  ptszMessageTimer, hwndParent);

    return msgBox.ShowMessageBox(pbStoppedByUser);
}

You can pass a BOOL * to get the info, if the user has pressed a button.

 

Thread-Safe

The map-access is enclosed by a CCriticalSection.

Sample

BOOL	stoppedByUser;
UINT	erg;

erg  = CDlgTimedMessageBox::TimedMessageBox(MB_YESNO|MB_ICONHAND, 
		"Please press a button", 
		"box-title", 
		5000, IDYES, 
		"\nin the next %lu sec !", 
		NULL, &stoppedByUser);

History

5.11.2000     posted to Code Project
14.11.2000   bugfixes for NT4
05.02.2001   bug reported when created with MBYES: defbutton then is IDCANCEL
05.02.2001   global function went to class-scope

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Markus Loibl



Germany Germany

Member



Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
GeneralMy vote of 1 PinmemberSudhindra Sathya1:26 19 Nov '10  
QuestionHow to show other icons in the messagebox.. PinmemberJigar Mehta20:48 23 Nov '04  
GeneralCompiling errors Pinmembershalala21:11 7 Oct '03  
GeneralRe: Compiling errors Pinmembercristitomi6:35 21 Mar '07  
Generaltimed out MessageBox PinmemberXeena6:53 2 Oct '02  
Generalbottons PinmemberAnonymous5:29 17 Jun '02  
GeneralIf you like this then.... PinmemberAnonymous7:23 12 Mar '02  
General"Fire and Forget" addition PinmemberM.Lansdaal14:53 12 Feb '02  
GeneralTimer PinmemberJoachim2:59 12 Nov '01  
GeneralRe: Timer Pinmembermloibl21:10 12 Nov '01  
GeneralRe: Timer PinmemberAlfred Rohr5:04 22 Nov '01  
GeneralMemory Leaks Pinmembereljkmw17:53 22 Aug '01  
GeneralRe: Memory Leaks PinmemberAlan Adams11:04 28 Oct '04  
QuestionHOW? PinmemberTGWG7:00 6 Jul '01  
AnswerRe: HOW? PinmemberMLoibl20:50 17 Jul '01  
GeneralMissing include PinmemberAnonymous4:52 6 Jul '01  
GeneralAlways on top Pinmembernewbie3:20 22 Jun '01  
GeneralRe: Always on top PinmemberMLoibl20:56 17 Jul '01  
QuestionAfxIsDescendant() ? PinmemberPeter Sjöström5:58 28 Mar '01  
AnswerRe: AfxIsDescendant() ? PinmemberMLoibl20:10 28 Mar '01  
AnswerRe: AfxIsDescendant() ? PinmemberWes Jones13:19 17 Jul '01  
GeneralIcky global functions! PinmemberPaul Wolfensberger4:15 17 Nov '00  
GeneralRe: Icky global functions! PinmemberMLoibl3:51 5 Feb '01  
GeneralRe: Icky global functions! PinmemberMLoibl9:13 5 Feb '01  
GeneralCrashes immediately on NT4 PinmemberAnonymous1:40 13 Nov '00  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web01 | 2.5.120517.1 | Last Updated 13 Feb 2001
Article Copyright 2000 by Markus Loibl
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid