[C++]Simple nativated timer class
從.NET跨足到C++筆者還是不太習慣C++的寫作方式,比較習慣於用.NET的寫法來寫C++程式,既然C++也開始具備屬性跟事件,C++也能寫的跟.NET程式很像。這邊筆者試寫了一個簡單的C++ Nativated Timer,希望使用上會比較接近.NET的寫作習慣,這邊將之稍做整理。
程式的部分主要有EventArgs與Timer兩個類別,程式碼如下:
EventArgs.h
#pragma once
class EventArgs
{
#pragma region Constructor & DeConstructor
public:
EventArgs(void);
virtual ~EventArgs(void);
#pragma endregion
};
EventArgs.Cpp
#include "stdafx.h"
#include "EventArgs.h"
#pragma region Constructor & DeConstructor
EventArgs::EventArgs(void)
{
}
EventArgs::~EventArgs(void)
{
}
#pragma endregion
Timer.h
#pragma once
#include "EventArgs.h"
#include <Windows.h>
[event_source]
[event_receiver]
class Timer
{
#pragma region Var
private:
int _nTimerID;
int _nInterval;
bool _bIsEnabled;
#pragma endregion
#pragma region Private Property
private:
__declspec(property(get=Get_nTimerID,put=Set_nTimerID))
int m_nTimerID;
#pragma endregion
#pragma region Public Property
public:
__declspec(property(get=Get_nInterval,put=Set_nInterval))
int m_nInterval;
__declspec(property(get=Get_bIsEnabled,put=Set_bIsEnabled))
bool m_bIsEnabled;
#pragma endregion
#pragma region Event
public:
__event void IntervalChanging(void* sender, EventArgs* e);
__event void IntervalChanged(void* sender, EventArgs* e);
__event void IsEnabledChanging(void* sender, EventArgs* e);
__event void IsEnabledChanged(void* sender, EventArgs* e);
__event void Tick(void* sender, EventArgs* e);
#pragma endregion
#pragma region Constructor & DeConstructor
public:
Timer(int nInterval = 0);
Timer(bool bIsEnabled, int nInterval = 0);
virtual ~Timer(void);
#pragma endregion
#pragma region Property Process Method
private:
inline int Get_nTimerID()
{
return _nTimerID;
}
inline void Set_nTimerID(int value)
{
if(_nTimerID == value)
return;
_nTimerID = value;
}
public:
inline int Get_nInterval()
{
return _nInterval;
}
inline void Set_nInterval(int value)
{
if(_nInterval == value)
return;
EventArgs e;
OnIntervalChanging(&e);
_nInterval = value;
OnIntervalChanged(&e);
}
inline bool Get_bIsEnabled()
{
return _bIsEnabled;
}
inline void Set_bIsEnabled(bool value)
{
if(_bIsEnabled == value)
return;
EventArgs e;
OnIsEnabledChanging(&e);
_bIsEnabled = value;
OnIsEnabledChanged(&e);
}
#pragma endregion
#pragma region Private Method
private:
void Init(bool bIsEnabled = false, int nInterval = 0);
void UnBindingEvent();
void BindingEvent();
void KillTimer();
void SetTimer();
static void CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime);
#pragma endregion
#pragma region Protected Method
protected:
virtual void Reset(bool bIsInit = false);
void OnIntervalChanging(EventArgs* e)
{
__raise IntervalChanging(this, e);
}
void OnIntervalChanged(EventArgs* e)
{
__raise IntervalChanged(this, e);
}
void OnIsEnabledChanging(EventArgs* e)
{
__raise IsEnabledChanging(this, e);
}
void OnIsEnabledChanged(EventArgs* e)
{
__raise IsEnabledChanged(this, e);
}
void OnTick(EventArgs* e)
{
__raise Tick(this, e);
}
#pragma endregion
#pragma region Public Method
public:
void Start();
void Stop();
#pragma endregion
#pragma region Event Process
private:
void Timer_IsEnabledChanged(void* sender, EventArgs* e);
void Timer_IntervalChanged(void* sender, EventArgs* e);
#pragma endregion
};
Timer.Cpp
#include "stdafx.h"
#include "Timer.h"
#include <map>
using namespace std;
map<int, Timer*> g_TimerPool;
#pragma region Constructor & DeConstructor
Timer::Timer(int nInterval)
{
Init(false, nInterval);
}
Timer::Timer(bool bIsEnabled, int nInterval)
{
Init(bIsEnabled, nInterval);
}
Timer::~Timer(void)
{
Reset();
}
#pragma endregion
#pragma region Private Method
void Timer::Init(bool bIsEnabled, int nInterval)
{
Reset(true);
m_bIsEnabled = bIsEnabled;
m_nInterval = nInterval;
BindingEvent();
}
void Timer::UnBindingEvent()
{
__unhook(&Timer::IsEnabledChanged, this, &Timer::Timer_IsEnabledChanged);
__unhook(&Timer::IntervalChanged, this, &Timer::Timer_IntervalChanged);
}
void Timer::BindingEvent()
{
UnBindingEvent();
__hook(&Timer::IsEnabledChanged, this, &Timer::Timer_IsEnabledChanged);
__hook(&Timer::IntervalChanged, this, &Timer::Timer_IntervalChanged);
}
void Timer::KillTimer()
{
if(!m_nTimerID)
return;
::KillTimer(NULL, m_nTimerID);
g_TimerPool[m_nTimerID] = NULL;
m_nTimerID = 0;
}
void Timer::SetTimer()
{
KillTimer();
if(!m_bIsEnabled)
return;
if(m_nTimerID)
return;
m_nTimerID = ::SetTimer(NULL, NULL, m_nInterval, TimerProc);
g_TimerPool[m_nTimerID] = this;
}
void CALLBACK Timer::TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
{
if(g_TimerPool.find(idEvent) == g_TimerPool.end())
return;
Timer* pTimer = g_TimerPool[idEvent];
if(!pTimer)
return;
EventArgs eventArgs;
pTimer->OnTick(&eventArgs);
}
#pragma endregion
#pragma region Protected Method
void Timer::Reset(bool bIsInit)
{
if(bIsInit)
{
_nTimerID = 0;
}
__unhook(this);
UnBindingEvent();
_bIsEnabled = false;
_nInterval = 0;
if(_nTimerID)
{
KillTimer();
_nTimerID = 0;
}
}
#pragma endregion
#pragma region Public Method
void Timer::Start()
{
m_bIsEnabled = true;
}
void Timer::Stop()
{
m_bIsEnabled = false;
}
#pragma endregion
#pragma region Event Process
void Timer::Timer_IsEnabledChanged(void* sender, EventArgs* e)
{
SetTimer();
}
void Timer::Timer_IntervalChanged(void* sender, EventArgs* e)
{
SetTimer();
}
#pragma endregion
使用上會像下面這樣,設定Timer的週期與是否啟用,並繫結事件處理常式做對應的處理。
// ConsoleApplication9.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <Windows.h>
#include "Timer.h"
class TestClass
{
public:
Timer m_Timer;
int m_nTickCount;
TestClass()
{
m_nTickCount = 0;
__hook(&Timer::Tick, &m_Timer, &TestClass::Timer_Tick);
m_Timer.m_nInterval = 1000;
m_Timer.m_bIsEnabled = true;
}
void Timer_Tick(void* sender, EventArgs* e)
{
++m_nTickCount;
printf("Timer_Tick\r\n");
}
};
int _tmain(int argc, _TCHAR* argv[])
{
MSG msg;
TestClass testObj;
while (testObj.m_nTickCount < 10)
{
GetMessage(&msg, NULL, 0, 0);
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
運行後可每秒寫出一個Timer_Tick的字串,運行十秒後結束。