How to use High Resolution Timer on MS-Windows


高精度タイマをWindowsで使うためのクラスです。 この実態はMultimedia Timerです。winmm.libをリンクする必要があります。

コンパイル時に、timeSetEventの第3引数を切り詰めたといった警告が出ますが 問題なく動きます。本来ならFunctorを使って実装すべきでしょう。

実装

// class MultiMediaTimer
/*

   Windows Multimedia Timer wrapper class
   Copyright (C)2004 Chome <chome@argv.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License
   as published by the Free Software Foundation; either version 2
   of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

// This class requierd to link 'Winmm.lib'


#include <windows.h>
#include <mmsystem.h>

#ifndef _JM6XXU_MULTIMEDIATIMER_H
#define _JM6XXU_MULTIMEDIATIMER_H


class MultiMediaTimer{
public:

  // 'run' function is called when peried specified by constructor is reached.
  // It is requiered to overried this function.
  virtual void run() = 0;

  // create MultiMediaTimer instance.
  // See 'timeSetEvent' in MSDN Library
  //
  // Parameters:
  // uDelay: interval of timer in milliseconds
  // fPeriodic: if true, called run member function periodically, otherwise one shot.
  // uResolution: time resolution of timer event in milliseconds.
  inline MultiMediaTimer(UINT uDelay, BOOL fPeriodic = true, UINT uResolution=0):
    _isKilled(true),
    _isPeriodic(fPeriodic),
    _uDelay(uDelay),
    _uResolution(uResolution)
  {};


  // start timer
  inline void start(){
    UINT uEvent;
    if(true == _isPeriodic)
      uEvent = TIME_PERIODIC;
    else
      uEvent = TIME_ONESHOT;

    _isKilled = false;
    _uTimerID = timeSetEvent(_uDelay, _uResolution, MultiMediaTimer::TimerHandler, (DWORD)this, TIME_PERIODIC);
  }

  // kill timer.
  inline void kill(){
    // if one shot timer, this function has nothing to do.
    if(false == _isPeriodic)
      return;

    if(_isKilled == false)
      timeKillEvent(_uTimerID);
    _isKilled = true;
  }

private:
  UINT _uTimerID; // timer id
  UINT _uResolution;  // time resolution
  UINT _uDelay; // timer interval
  BOOL _isKilled;
  BOOL _isPeriodic;

private:
  inline void static CALLBACK TimerHandler(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2){
    ((MultiMediaTimer*)dwUser)->run();
  };

  MultiMediaTimer();
};

#endif  //_JM6XXU_MULTIMEDIATIMER_H

Sample

#include <windows.h>
#include <mmsystem.h>
#include <iostream>

#include "MultiMediaTimer.h"

class TestTimer: public MultiMediaTimer{
public:
  TestTimer():MultiMediaTimer(100){};
  void run(){
    SYSTEMTIME time;
    GetLocalTime(&time);
    std::cout<< time.wMilliseconds<< std::endl;
  };
};



int main(int argc, char* argv[])
{
    // print multi media timer resolution
    TIMECAPS caps;

    timeGetDevCaps(&caps, sizeof(caps));
    std::cout<< "Timer resolution is from "<< caps.wPeriodMin<< " to "<< caps.wPeriodMax<< std::endl;

    TestTimer mmt;
    mmt.start();
    Sleep(1000);

    mmt.kill();
    return 0;
}