In a previous article I showed how to make AfxMessageBox to display a message box with auto-close, by using a CBT hook.
One reader suggested that whould be nice if the message box displays also the time left until auto-closing. I thought that’s a very good idea and promissed an update. Here it is!

Of course, may be more than one solution. I chose one which appends “Time left: xxx sec.” in the bottom of the built-in static text control. For this purpose, I added two private methods to CAutoMessageBox class:
- CAutoMessageBox::_InitStaticTextCtrl – initializes the static contol: finds the static control, keeps in mind the initial text, makes space for an extra-line of text, and assigns an ID to be used later.
void CAutoMessageBox::_InitStaticTextCtrl() { // search for static text control CWnd* pWndCtrl = GetWindow(GW_CHILD); while(NULL != pWndCtrl->GetSafeHwnd()) { const int nMaxCount = 63; CString strClass; ::GetClassName(pWndCtrl->m_hWnd, strClass.GetBufferSetLength(nMaxCount), nMaxCount); DWORD dwStyle = pWndCtrl->GetStyle(); strClass.ReleaseBuffer(); if(!strClass.CompareNoCase(_T("STATIC")) && !(dwStyle & SS_ICON)) { // set static control ID ::SetWindowLong(pWndCtrl->m_hWnd, GWL_ID, IDC_STATIC_TEXT); // keep in mind the initial text pWndCtrl->GetWindowText(m_strIntitalText); // calculate extra-line height and width CClientDC dc(this); CFont* pFont = pWndCtrl->GetFont(); ASSERT(NULL != pFont); CFont* pOldFont = dc.SelectObject(pFont); CRect rcText(0, 0, 0, 0); dc.DrawText(CString(_T("Time left: 999 sec.")), rcText, DT_SINGLELINE|DT_CALCRECT); dc.SelectObject(pOldFont); // add extra-line space CRect rcCtrl; pWndCtrl->GetWindowRect(rcCtrl); ScreenToClient(rcCtrl); rcCtrl.bottom += rcText.Height(); const int nExtraWidth = rcText.Width() - rcCtrl.Width(); if(nExtraWidth > 0) rcCtrl.right += nExtraWidth; pWndCtrl->MoveWindow(rcCtrl); break; } // get next child control pWndCtrl = pWndCtrl->GetWindow(GW_HWNDNEXT); } }
- CAutoMessageBox::_SetStaticTextCtrl – sets the text which contains time left.
void CAutoMessageBox::_SetStaticTextCtrl() { UINT nRemained = (m_nTimeOut - m_nElapsed) / 1000 + 1; CWnd* pWndStatic = GetDlgItem(IDC_STATIC_TEXT); ASSERT(NULL != pWndStatic->GetSafeHwnd()); CString strText; strText.Format(_T("%s\nTime left: %u sec."), m_strIntitalText, nRemained); pWndStatic->SetWindowText(strText); }
For more implementation details of CAutoMessageBox class, download and have a look in the attached demo project.
See also
- Codexpert blog: AfxMessageBox with Auto-close (Part 1)
Is there a way to handle the messagebox buttons size ? I mean, what if I want to modify “Ok” button text, with “Go to next file” button text …
I had found here something appropiate:
http://www.codeguru.com/cpp/w-p/win32/messagebox/article.php/c10873/MessageBox-with-Custom-Button-Captions.htm
Here is code that stretch ABORT button, for ex.
LRESULT CAutoMessageBox::OnInitDialog(WPARAM wParam, LPARAM lParam)
{
if(m_nTimeOut > 0)
{
_InitStaticTextCtrl();
SetTimer(0, m_nTimerStep, NULL);
}
if(m_bShowProgress)
{
VERIFY(_AddProgressCtrl());
// m_progress.SetRange(0, m_nTimeOut);
m_progress.SetRange32(0, m_nTimeOut); // use 32-bit limit for a larger range
m_progress.SetPos(m_nElapsed);
}
CButton* pAbort = (CButton*)GetDlgItem(IDABORT);
if(pAbort)
{
CRect rect;
pAbort->GetWindowRect(&rect);
ScreenToClient(&rect);
rect.OffsetRect(CPoint(-20, 0));
rect.right += 20;
pAbort->MoveWindow(rect);
}
return TRUE;
}
I still have a question: I don’t know why doesn’t work MB_DEFBUTTON2 or MB_DEFBUTTON3 style flags on CAutoMessageBox … as long I didn’t use CAutoMessageBox on demo project, everything is all right.