Скачать исходник - 3 Kb
Цель этого примера
Иногда возникает необходимость показать
пользователю стандартное диалоговое
окошко типа Yes/No , и, если пользователь не даёт
ответа, то по истечении определённого
интервала времени закрыть этот диалог.
Основы
Перед вызовом MessageBox
, необходимо
проинсталировать таймер. Когда окно закрывается,
то в окно MessageBox поступает сообщение WM_COMMAND
.
Timer-Callback
Я решил собрать всю информацию передающуюся в MessageBox
(Заголовок, Текст, Флаги ...) в классе.
Но есть одна проблемма: с функцией SetTimer()
может
быть инсталлирована только статическая
timer-callback-процедура: которая не может получить
доступа к членам класса (так как статическая).
Для решения этой проблеммы я вставил мап(Map) для
хранения сообщения класса для timer-id:
Заголовок:
class CDlgTimedMessageBox
{
public:
// ...
UINT ShowMessageBox(BOOL *pbStoppedByUser=NULL);
// ...
static void GlobalTimerProc(HWND hwnd, UINT uiMsg, UINT idEvent, DWORD dwTime);
void LocalTimerProc(void);
// ...
static CMapPtrToPtr m_mapTimerIdToClassMe;
protected:
UINT m_idTimer;
};
Исходник:
UINT CDlgTimedMessageBox::ShowMessageBox(BOOL *pbStoppedByUser)
{
// ...
m_idTimer = ::SetTimer(NULL, 0, 1000, (TIMERPROC) CDlgTimedMessageBox::GlobalTimerProc);
CDlgTimedMessageBox::m_mapTimerIdToClassMe.SetAt((void*)m_idTimer, this);
// ...
::MessageBox(...)
// ...
}
void CDlgTimedMessageBox::GlobalTimerProc(HWND hwnd, UINT uiMsg, UINT idEvent, DWORD dwTime)
{
CDlgTimedMessageBox *pMe = NULL;
// Находим timer-id сообщения для класса
CDlgTimedMessageBox::m_mapTimerIdToClassMe.Lookup((void*)idEvent, (void *&) pMe);
if( pMe!=NULL )
pMe->LocalTimerProc();
}
void CDlgTimedMessageBox::LocalTimerProc(void)
{
// находим Message-Box-окно
// Calculate time since start
if( too long running )
{
// Закрываем MessageBox
}
else
{
// изменяем текст MessageBox
}
}
Находим 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);
}
Добавляем всё это в одну функцию
UINT 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);
}
Потокозащищённость
Доступ к карте включён через CCriticalSection.
Пример
BOOL stoppedByUser;
UINT erg;
erg = ::TimedMessageBox(MB_YESNO|MB_ICONHAND,
"Please press a button",
"box-title",
5000, IDYES,
"\nin the next %lu sec !",
NULL, &stoppedByUser);