Introduction
Setting a timer in C++/Win32 that fires once, normally requires a lot of work, considering that all you really want to do is wait a bit and execute a function, but not block mainline code execution. This simple class makes OneShot timers easy. No more struggling with static functions and 'this
' pointers.
Using the code
The only special instructions for using this class are:
- You must instantiate the timer object using
new
, because the object deletes itself after the timer fires.
- The target function is called using
PostMessage
, so there must be a MESSAGE_MAP
entry (either ON_MESSAGE
, or ON_COMMAND
) for the target function.
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
ON_COMMAND( IDC_DOCOMMAND, OnDoCommand )
ON_MESSAGE( IDC_DOMESSAGE, OnDoMessage )
END_MESSAGE_MAP()
void CMyClass::OnDoCommand()
{
return;
}
LRESULT CMyClass::OnDoMessage( WPARAM wParam,
LPARAM lParam )
{
return 0;
}
new CTimerOneShot( 2000, GetSafeHwnd(),
IDC_DOCOMMAND );
new CTimerOneShot( 2000, GetSafeHwnd(),
IDC_DOMESSAGE, 123, 456 );
#pragma once
class CTimerOneShot
{
public:
CTimerOneShot( int a_msecs, HWND a_targetHwnd,
int a_messageID, WPARAM a_wparam,
LPARAM a_lparam )
{
m_timerID = (UINT) this;
m_targetHwnd = a_targetHwnd;
m_messageID = a_messageID;
m_lparam = a_lparam;
m_wparam = a_wparam;
m_msecs = a_msecs;
::SetTimer( a_targetHwnd, m_timerID,
m_msecs, TimerProcA );
}
static void CALLBACK EXPORT TimerProcA( HWND a_hwnd,
UINT ,
UINT a_timerID, DWORD a_systemtime )
{
CTimerOneShot* pOneShot = (CTimerOneShot*) a_timerID;
ASSERT( a_hwnd == pOneShot->m_targetHwnd );
::KillTimer( pOneShot->m_targetHwnd, a_timerID );
::PostMessage( pOneShot->m_targetHwnd,
pOneShot->m_messageID,
pOneShot->m_wparam,
pOneShot->m_lparam );
delete pOneShot;
}
CTimerOneShot( int a_msecs,
HWND a_targetHwnd, int a_commandID )
{
m_timerID = (UINT) this;
m_targetHwnd = a_targetHwnd;
m_commandID = a_commandID;
m_msecs = a_msecs;
::SetTimer( a_targetHwnd, m_timerID,
m_msecs, TimerProcB );
}
static void CALLBACK EXPORT TimerProcB( HWND a_hwnd,
UINT , UINT a_timerID,
DWORD a_systemtime )
{
CTimerOneShot* pOneShot = (CTimerOneShot*) a_timerID;
ASSERT( a_hwnd == pOneShot->m_targetHwnd );
::KillTimer( pOneShot->m_targetHwnd, a_timerID );
::PostMessage( pOneShot->m_targetHwnd,
WM_COMMAND, pOneShot->m_commandID, 0 );
delete pOneShot;
}
HWND m_targetHwnd;
int m_messageID;
int m_commandID;
LPARAM m_lparam;
WPARAM m_wparam;
UINT m_timerID;
int m_msecs;
};