好久没写点东西了,拿点东西凑凑数
实现一个Timer类说起来挺简单,但是如果有特殊的需要时也挺让人头痛的。
我就碰到一个需要在一个对象内部需要聚合多个定时器的需求,而且是真正相应Windows消息的定时器。
需求是BT但是也得想办法实现,想来想去还是Trunk技术实现起来最方便。
我们知道创建一个定时器需要调用一个Windows的Api函数:
UINT_PTR SetTimer(
HWND hWnd,
UINT_PTR nIDEvent,
UINT uElapse,
TIMERPROC lpTimerFunc
);
按照MSDN的说法最后一个参数需要传入一个回调函数,格式如下:
VOID CALLBACK TimerProc(
HWND hwnd,
UINT uMsg,
UINT_PTR idEvent,
DWORD dwTime
);
我想要达到的目标是,创建每个定时器对象时,分配一个成员函数做为回调函数,当该定时器消息到来时,该成员函数需要相应该消息。
下面说说具体实现,不知道Trunk的可以趁现在去查查资料。
头文件:
1
class
ZTimer
2 {
3 public :
4 ZTimer(DWORD Elapse = 1000 );
5 virtual ~ ZTimer();
6 VOID SetElapse(DWORD Elapse);
7 VOID SetOnTimer( void * pThis,DWORD FunAddr);
8 VOID Stop();
9 VOID Start();
10
11 protected :
12 DWORD m_Elapse;
13 UINT m_TimerID;
14 private :
15 BYTE m_thunk[ 8 + 2 * sizeof (DWORD * )];
16 };
17
2 {
3 public :
4 ZTimer(DWORD Elapse = 1000 );
5 virtual ~ ZTimer();
6 VOID SetElapse(DWORD Elapse);
7 VOID SetOnTimer( void * pThis,DWORD FunAddr);
8 VOID Stop();
9 VOID Start();
10
11 protected :
12 DWORD m_Elapse;
13 UINT m_TimerID;
14 private :
15 BYTE m_thunk[ 8 + 2 * sizeof (DWORD * )];
16 };
17
单元文件:
1
ZTimer::ZTimer(DWORD Elapse)
2 {
3 m_Elapse = Elapse;
4 m_TimerID = 0 ;
5 }
6 ZTimer:: ~ ZTimer()
7 {
8 Stop();
9 }
10 VOID ZTimer::SetElapse(DWORD Elapse)
11 {
12 Stop();
13 m_Elapse = Elapse;
14 m_TimerID = ::SetTimer(NULL, 0 ,m_Elapse,(TIMERPROC) & m_thunk[ 0 ]);
15 }
16 VOID ZTimer::SetOnTimer( void * pThis,DWORD FunAddr)
17 {
18 DWORD dwDistance = FunAddr - (DWORD) & m_thunk[ 0 ] - ( 8 + 2 * sizeof (DWORD * ));
19 /*
20 Encoded machine instruction Equivalent assembly languate notation
21 --------------------------- -------------------------------------
22 FF 34 24 push dword ptr [esp] ; Save (or duplicate) the Return Addr into stack
23 C7 44 24 04 ?? ?? ?? ?? mov dword ptr [esp+4], pThis ; Overwite the old Return Addr with 'this pointer'
24 E9 ?? ?? ?? ?? jmp dwProcPtr ; Jump to target message handler
25 */
26
27 m_thunk[ 7 + sizeof (DWORD * )] = 0xE9 ;
28
29 * ((DWORD * ) & m_thunk[ 0 ]) = 0x002434FF ;
30 * ((DWORD * ) & m_thunk[ 3 ]) = 0x042444C7 ;
31 * ((DWORD * ) & m_thunk[ 7 ]) = (DWORD)(pThis);
32 * ((DWORD * ) & m_thunk[ 8 + sizeof (DWORD * )]) = dwDistance;
33 }
34 VOID ZTimer::Stop()
35 {
36 if (m_TimerID != 0 )
37 {
38 ::KillTimer(NULL,m_TimerID);
39 m_TimerID = 0 ;
40 }
41 }
42 VOID ZTimer::Start()
43 {
44 Stop();
45 m_TimerID = ::SetTimer(NULL, 0 ,m_Elapse,(TIMERPROC) & m_thunk[ 0 ]);
46 }
47
48
2 {
3 m_Elapse = Elapse;
4 m_TimerID = 0 ;
5 }
6 ZTimer:: ~ ZTimer()
7 {
8 Stop();
9 }
10 VOID ZTimer::SetElapse(DWORD Elapse)
11 {
12 Stop();
13 m_Elapse = Elapse;
14 m_TimerID = ::SetTimer(NULL, 0 ,m_Elapse,(TIMERPROC) & m_thunk[ 0 ]);
15 }
16 VOID ZTimer::SetOnTimer( void * pThis,DWORD FunAddr)
17 {
18 DWORD dwDistance = FunAddr - (DWORD) & m_thunk[ 0 ] - ( 8 + 2 * sizeof (DWORD * ));
19 /*
20 Encoded machine instruction Equivalent assembly languate notation
21 --------------------------- -------------------------------------
22 FF 34 24 push dword ptr [esp] ; Save (or duplicate) the Return Addr into stack
23 C7 44 24 04 ?? ?? ?? ?? mov dword ptr [esp+4], pThis ; Overwite the old Return Addr with 'this pointer'
24 E9 ?? ?? ?? ?? jmp dwProcPtr ; Jump to target message handler
25 */
26
27 m_thunk[ 7 + sizeof (DWORD * )] = 0xE9 ;
28
29 * ((DWORD * ) & m_thunk[ 0 ]) = 0x002434FF ;
30 * ((DWORD * ) & m_thunk[ 3 ]) = 0x042444C7 ;
31 * ((DWORD * ) & m_thunk[ 7 ]) = (DWORD)(pThis);
32 * ((DWORD * ) & m_thunk[ 8 + sizeof (DWORD * )]) = dwDistance;
33 }
34 VOID ZTimer::Stop()
35 {
36 if (m_TimerID != 0 )
37 {
38 ::KillTimer(NULL,m_TimerID);
39 m_TimerID = 0 ;
40 }
41 }
42 VOID ZTimer::Start()
43 {
44 Stop();
45 m_TimerID = ::SetTimer(NULL, 0 ,m_Elapse,(TIMERPROC) & m_thunk[ 0 ]);
46 }
47
48
具体使用时:
1
class
MyTimerTest
2 {
3 ZTimer m_pTimer1;
4 ZTimer m_pTimer2;
5 public :
6 VOID CALLBACK OnTimer1(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
7 {
8 printf( " Timer1::OnTimer\n " );
9 }
10 VOID CALLBACK OnTimer2(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
11 {
12 printf( " Timer2::OnTimer\n " );
13 }
14
15
16 MyTimerTest()
17 {
18
19 m_pTimer1.SetOnTimer( this ,union_cast < DWORD > ( & MyTimerTest::OnTimer1));
20 m_pTimer1.Start();
21 m_pTimer2.SetOnTimer( this ,union_cast < DWORD > ( & MyTimerTest::OnTimer2));
22 m_pTimer2.Start();
23 }
24 virtual ~ MyTimerTest()
25 {
26 }
27 };
28
29
30 MyTimerTest timer;
31
32
33
34 int _tmain( int argc, _TCHAR * argv[])
35 {
36
37
38 MSG msg;
39 BOOL bRet;
40 while ( (bRet = GetMessage( & msg, NULL, 0 , 0 )) != 0 )
41 {
42 if (bRet == - 1 )
43 {
44 break ;
45 }
46 else
47 {
48 TranslateMessage( & msg);
49 DispatchMessage( & msg);
50 }
51 }
52
53 return 0 ;
54 }
55
2 {
3 ZTimer m_pTimer1;
4 ZTimer m_pTimer2;
5 public :
6 VOID CALLBACK OnTimer1(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
7 {
8 printf( " Timer1::OnTimer\n " );
9 }
10 VOID CALLBACK OnTimer2(HWND hwnd,UINT uMsg,UINT_PTR idEvent,DWORD dwTime)
11 {
12 printf( " Timer2::OnTimer\n " );
13 }
14
15
16 MyTimerTest()
17 {
18
19 m_pTimer1.SetOnTimer( this ,union_cast < DWORD > ( & MyTimerTest::OnTimer1));
20 m_pTimer1.Start();
21 m_pTimer2.SetOnTimer( this ,union_cast < DWORD > ( & MyTimerTest::OnTimer2));
22 m_pTimer2.Start();
23 }
24 virtual ~ MyTimerTest()
25 {
26 }
27 };
28
29
30 MyTimerTest timer;
31
32
33
34 int _tmain( int argc, _TCHAR * argv[])
35 {
36
37
38 MSG msg;
39 BOOL bRet;
40 while ( (bRet = GetMessage( & msg, NULL, 0 , 0 )) != 0 )
41 {
42 if (bRet == - 1 )
43 {
44 break ;
45 }
46 else
47 {
48 TranslateMessage( & msg);
49 DispatchMessage( & msg);
50 }
51 }
52
53 return 0 ;
54 }
55
其中union_cast函数的定义如下:
1
template
<
class
ToType,
class
FromType
>
2 ToType & union_cast(FromType f)
3 {
4 union
5 {
6 FromType _f;
7 ToType _t;
8 }ut;
9
10 ut._f = f;
11 return ut._t;
12 }
2 ToType & union_cast(FromType f)
3 {
4 union
5 {
6 FromType _f;
7 ToType _t;
8 }ut;
9
10 ut._f = f;
11 return ut._t;
12 }
回头看看,有点奇技淫巧的意味。。。算了,不管他抓住耗子就是好猫 !