65.9K
CodeProject is changing. Read more.
Home

Timers in MFC / C++

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.20/5 (5 votes)

Jan 17, 2006

viewsIcon

94747

Implementing one-shot timers.

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.
// Map the function you want to call.
// You can use either Command or Message format:
BEGIN_MESSAGE_MAP(CMyClass, CWnd)
       ON_COMMAND( IDC_DOCOMMAND, OnDoCommand )
    ON_MESSAGE( IDC_DOMESSAGE, OnDoMessage )
END_MESSAGE_MAP()
// Your Functions
void CMyClass::OnDoCommand()
{
   return;
}

LRESULT CMyClass::OnDoMessage( WPARAM wParam, 
                               LPARAM lParam )
{
   return 0;
}
// In your code, fire the OneShots. Remember they must use new, as 
//they are self deleting once the timer fires.
//The TimerID is guaranteed to be unique as the object 
//exists for the the duration of the timer.

new CTimerOneShot( 2000, GetSafeHwnd(), 
                   IDC_DOCOMMAND ); // Command Version

// or

new CTimerOneShot( 2000, GetSafeHwnd(), 
                   IDC_DOMESSAGE, 123, 456 ); // Message Version
// And here is the OneShot class. 
#pragma once

class CTimerOneShot
{
public:

   // MESSAGE Format
   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 /*WM_TIMER*/, 
          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;
   }

   // COMMAND Format
   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 /*WM_TIMER*/, 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;
};