好久没写点东西了,拿点东西凑凑数
实现一个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 }
回头看看,有点奇技淫巧的意味。。。算了,不管他抓住耗子就是好猫 !![]()
浙公网安备 33010602011771号