Skip navigation links

Source code for C_Timer

Download

The source files for this module are listed below.  You can also download the module C_Timer as a zip archive; this archive contains all the source files and documentation.

Description

CTimer allows you to receive events on regular intervals without handling the Windows timer messages yourself.

Information

This source code also uses our signal/slot library and our CSubclassedWindow class.  You can also download these at our website.

To start using a timer, you first have to initialize it.  Since the timer uses the standard Windows timer messages, the timer needs to have a window to route the messages through.  This is done by subclassing the window.  Since each timer has it's own ID behind the scenes, you can attach as many timers to a window as desired.  You can re-initialize a timer to a different window in order to use that window and stop using the previous one.

Once you have initialized the timer, you can call it's Start and Stop methods in order to start and stop the timer events.  Calling Start two times in a row will restart the timer on the second call with the given new interval.  When you stop the timer, you can also let the timer generate a last timer event so the event sequence is terminated.  This timer event is however fired immediately.  The current state of the timer can be retrieved by calling the method IsRunning.

The event that is raised has no return value.  It is only meant for informative purposes.

Notes / todo's

  • Add an extra parameter to the Stop method to have the last event sent not immediately but at the expected timer interval.

Files

Each file belonging to this source code module is listed below.

Timer.h

/*******************************************************************************

  Version: 3
  Author:  Carl Colijn, TwoLogs
  Contact: c.colijn@twologs.com
  Source:  http://www.twologs.com/sourcecode

  This code is freely distributable, as long as this comment remains intact.
  If you find this source useful, you may use this code in your own projects
  free of charge, but some acknowledgement to the author of this code is always
  appreciated :)
  The source is however distributed 'as is' without waranty and/or support, and
  may not be fit for each and every application.  Use it at your own discretion
  and at your own risk.
  The source already has undergone testing.  This doesn't mean however that all
  bugs are removed from this piece of code.  If you find one of them, please
  contact me about it.  I can however not guarantee when and if the bug will be
  fixed.

  More information about this module can be found in the accompanying HTML file.

*******************************************************************************/

#ifndef INCLUDE_TWOLOGS_COMMON_TIMER_H
#define INCLUDE_TWOLOGS_COMMON_TIMER_H

#include "..\C_SubclassedWindow\SubclassedWindow.h"
#include "..\C_SignalSlot\Signal.h"

class CTimer;

// Notifies when the timer went off
struct CTimerWentOffEvent: public CEventTypeNoResult {
  CTimer* poTimer;
};

class CTimer:
  private CSubclassedWindow,
  public CSignal<CTimerWentOffEvent> {
public:
  // Con- & destructor
  CTimer();
  virtual ~CTimer();

  // (Re-)initializes the timer to use the given window
  void Initialize(HWND hWindow);

  // Starts or restarts the timer
  void Start(UINT nMillisecondInterval);

  // Stops the timer
  void Stop(bool bRaiseTimerEvent);

  // Whether the timer is running
  bool IsRunning() const;

private:
  // The last used ID
  static DWORD m_nLastUsedID;

  // Our ID
  DWORD m_nID;

  // The window's handle
  HWND m_hWindow;

  // Whether the timer is running
  bool m_bRunning;

  // Raises the timer event
  void RaiseTimerEvent();

  // Processes the given message
  void ProcessMessage(CMessage& oMsg);
};

#endif // INCLUDE_TWOLOGS_COMMON_TIMER_H

Timer.cpp

/*******************************************************************************

  Version: 3
  Author:  Carl Colijn, TwoLogs
  Contact: c.colijn@twologs.com
  Source:  http://www.twologs.com/sourcecode

  This code is freely distributable, as long as this comment remains intact.
  If you find this source useful, you may use this code in your own projects
  free of charge, but some acknowledgement to the author of this code is always
  appreciated :)
  The source is however distributed 'as is' without waranty and/or support, and
  may not be fit for each and every application.  Use it at your own discretion
  and at your own risk.
  The source already has undergone testing.  This doesn't mean however that all
  bugs are removed from this piece of code.  If you find one of them, please
  contact me about it.  I can however not guarantee when and if the bug will be
  fixed.

  More information about this module can be found in the accompanying HTML file.

*******************************************************************************/

#include "Timer.h"

// The last used ID
DWORD CTimer::m_nLastUsedID = 0;

// Con- & destructor
CTimer::CTimer():
 m_nID(m_nLastUsedID++),
 m_hWindow(NULL),
 m_bRunning(false) {
}
CTimer::~CTimer() {
  Stop(false);
}

// (Re-)initializes the timer to use the given window
void CTimer::Initialize(HWND hWindow) {
  // Look if to detach from a previous window
  if (m_hWindow != NULL) {
    // Yes -> do so
    StopSubclassing(m_hWindow);
  }

  // Note the window to use
  m_hWindow = hWindow;

  // And start subclassing it, if needed
  if (m_hWindow != NULL) {
    Subclass(m_hWindow);
  }
}

// Starts or restarts the timer
void CTimer::Start(UINT nMillisecondInterval) {
  if (m_hWindow != NULL) {
    SetTimer(m_hWindow, m_nID, nMillisecondInterval, NULL);
    m_bRunning = true;
  }
}

// Stops the timer
void CTimer::Stop(bool bRaiseTimerEvent) {
  // Kill the timer
  if (m_hWindow != NULL) {
    KillTimer(m_hWindow, m_nID);
    m_bRunning = false;
  }

  // And look if to raise a final timer event
  if (bRaiseTimerEvent) {
    // Yes -> do so
    RaiseTimerEvent();
  }
}

// Whether the timer is running
bool CTimer::IsRunning() const {
  return m_bRunning;
}

// Raises the timer event
void CTimer::RaiseTimerEvent() {
  CTimerWentOffEvent oEvent;
  oEvent.poTimer = this;
  CSignal<CTimerWentOffEvent>::RaiseEvent(oEvent);
}

// Processes the given message
void CTimer::ProcessMessage(CMessage& oMsg) {
  // Look if it's a timer message
  oMsg.bStop = false;
  if (oMsg.eCode == WM_TIMER) {
    // Yes -> look if it's our timer
    if (oMsg.nWParam == m_nID) {
      // Yes -> raise the timer event
      oMsg.bStop = true;
      RaiseTimerEvent();
    }
  }
}