SetWaitableTimer函数非凝滞定时
1 'clsWaitableTimer.cls 中代码
2
3 Option Explicit
4 Private Type FILETIME
5 dwLowDateTime As Long
6 dwHighDateTime As Long
7 End Type
8
9 Private Const WAIT_ABANDONED& = &H80&
10 Private Const WAIT_ABANDONED_0& = &H80&
11 Private Const WAIT_FAILED& = -1&
12 Private Const WAIT_IO_COMPLETION& = &HC0&
13 Private Const WAIT_OBJECT_0& = 0
14 Private Const WAIT_OBJECT_1& = 1
15 Private Const WAIT_TIMEOUT& = &H102&
16 Private Const INFINITE = &HFFFF
17 Private Const ERROR_ALREADY_EXISTS = 183&
18 Private Const QS_HOTKEY& = &H80
19 Private Const QS_KEY& = &H1
20 Private Const QS_MOUSEBUTTON& = &H4
21 Private Const QS_MOUSEMOVE& = &H2
22 Private Const QS_PAINT& = &H20
23 Private Const QS_POSTMESSAGE& = &H8
24 Private Const QS_SENDMESSAGE& = &H40
25 Private Const QS_TIMER& = &H10
26 Private Const QS_MOUSE& = (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
27 Private Const QS_INPUT& = (QS_MOUSE Or QS_KEY)
28 Private Const QS_ALLEVENTS& = (QS_INPUT Or QS_POSTMESSAGE Or QS_TIMER Or QS_PAINT Or QS_HOTKEY)
29 Private Const QS_ALLINPUT& = (QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or QS_KEY)
30
31 Private Const UNITS = 4294967296#
32 Private Const MAX_LONG = -2147483648#
33
34 Private Declare Function CreateWaitableTimer Lib "kernel32" Alias "CreateWaitableTimerA" (ByVal lpSemaphoreAttributes As Long, ByVal bManualReset As Long, ByVal lpName As String) As Long
35 Private Declare Function OpenWaitableTimer Lib "kernel32" Alias "OpenWaitableTimerA" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As String) As Long
36 Private Declare Function SetWaitableTimer Lib "kernel32" (ByVal hTimer As Long, lpDueTime As FILETIME, ByVal lPeriod As Long, ByVal pfnCompletionRoutine As Long, ByVal lpArgToCompletionRoutine As Long, ByVal fResume As Long) As Long
37 Private Declare Function CancelWaitableTimer Lib "kernel32" (ByVal hTimer As Long)
38 Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
39 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
40 Private Declare Function MsgWaitForMultipleObjects Lib "user32" (ByVal nCount As Long, pHandles As Long, ByVal fWaitAll As Long, ByVal dwMilliseconds As Long, ByVal dwWakeMask As Long) As Long
41
42 Private mlTimer As Long
43
44 Private Sub Class_Terminate()
45 On Error Resume Next
46 If mlTimer <> 0 Then CloseHandle mlTimer
47 End Sub
48
49 Public Sub Wait(MilliSeconds As Long)
50 On Error GoTo ErrHandler
51 Dim ft As FILETIME
52 Dim lBusy As Long
53 Dim lRet As Long
54 Dim dblDelay As Double
55 Dim dblDelayLow As Double
56
57 mlTimer = CreateWaitableTimer(0, True, App.EXEName & "Timer" & Format$(Now(), "NNSS"))
58
59 If Err.LastDllError <> ERROR_ALREADY_EXISTS Then
60 ft.dwLowDateTime = -1
61 ft.dwHighDateTime = -1
62 lRet = SetWaitableTimer(mlTimer, ft, 0, 0, 0, 0)
63 End If
64
65 dblDelay = CDbl(MilliSeconds) * 10000#
66
67 ft.dwHighDateTime = -CLng(dblDelay / UNITS) - 1
68 dblDelayLow = -UNITS * (dblDelay / UNITS - Fix(CStr(dblDelay / UNITS)))
69
70 If dblDelayLow < MAX_LONG Then dblDelayLow = UNITS + dblDelayLow
71
72 ft.dwLowDateTime = CLng(dblDelayLow)
73 lRet = SetWaitableTimer(mlTimer, ft, 0, 0, 0, False)
74
75 Do
76 lBusy = MsgWaitForMultipleObjects(1, mlTimer, False, INFINITE, QS_ALLINPUT&)
77 DoEvents
78 Loop Until lBusy = WAIT_OBJECT_0
79
80
81 CloseHandle mlTimer
82 mlTimer = 0
83 Exit Sub
84
85 ErrHandler:
86 Err.Raise Err.Number, Err.Source, "[clsWaitableTimer.Wait]" & Err.Description
87 End Sub
88
89 'FORM中代码
90
91 Private Sub cmdWaitTimer_Click()
92 Dim objTimer As clsWaitableTimer
93 Set objTimer = New clsWaitableTimer
94
95 cmdWaitTimer.Enabled = False
96 objTimer.Wait 5000 '5 秒
97 cmdWaitTimer.Enabled = True
98 Set objTimer = Nothing
99 End Sub
100
101
2
3 Option Explicit
4 Private Type FILETIME
5 dwLowDateTime As Long
6 dwHighDateTime As Long
7 End Type
8
9 Private Const WAIT_ABANDONED& = &H80&
10 Private Const WAIT_ABANDONED_0& = &H80&
11 Private Const WAIT_FAILED& = -1&
12 Private Const WAIT_IO_COMPLETION& = &HC0&
13 Private Const WAIT_OBJECT_0& = 0
14 Private Const WAIT_OBJECT_1& = 1
15 Private Const WAIT_TIMEOUT& = &H102&
16 Private Const INFINITE = &HFFFF
17 Private Const ERROR_ALREADY_EXISTS = 183&
18 Private Const QS_HOTKEY& = &H80
19 Private Const QS_KEY& = &H1
20 Private Const QS_MOUSEBUTTON& = &H4
21 Private Const QS_MOUSEMOVE& = &H2
22 Private Const QS_PAINT& = &H20
23 Private Const QS_POSTMESSAGE& = &H8
24 Private Const QS_SENDMESSAGE& = &H40
25 Private Const QS_TIMER& = &H10
26 Private Const QS_MOUSE& = (QS_MOUSEMOVE Or QS_MOUSEBUTTON)
27 Private Const QS_INPUT& = (QS_MOUSE Or QS_KEY)
28 Private Const QS_ALLEVENTS& = (QS_INPUT Or QS_POSTMESSAGE Or QS_TIMER Or QS_PAINT Or QS_HOTKEY)
29 Private Const QS_ALLINPUT& = (QS_SENDMESSAGE Or QS_PAINT Or QS_TIMER Or QS_POSTMESSAGE Or QS_MOUSEBUTTON Or QS_MOUSEMOVE Or QS_HOTKEY Or QS_KEY)
30
31 Private Const UNITS = 4294967296#
32 Private Const MAX_LONG = -2147483648#
33
34 Private Declare Function CreateWaitableTimer Lib "kernel32" Alias "CreateWaitableTimerA" (ByVal lpSemaphoreAttributes As Long, ByVal bManualReset As Long, ByVal lpName As String) As Long
35 Private Declare Function OpenWaitableTimer Lib "kernel32" Alias "OpenWaitableTimerA" (ByVal dwDesiredAccess As Long, ByVal bInheritHandle As Long, ByVal lpName As String) As Long
36 Private Declare Function SetWaitableTimer Lib "kernel32" (ByVal hTimer As Long, lpDueTime As FILETIME, ByVal lPeriod As Long, ByVal pfnCompletionRoutine As Long, ByVal lpArgToCompletionRoutine As Long, ByVal fResume As Long) As Long
37 Private Declare Function CancelWaitableTimer Lib "kernel32" (ByVal hTimer As Long)
38 Private Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Long) As Long
39 Private Declare Function WaitForSingleObject Lib "kernel32" (ByVal hHandle As Long, ByVal dwMilliseconds As Long) As Long
40 Private Declare Function MsgWaitForMultipleObjects Lib "user32" (ByVal nCount As Long, pHandles As Long, ByVal fWaitAll As Long, ByVal dwMilliseconds As Long, ByVal dwWakeMask As Long) As Long
41
42 Private mlTimer As Long
43
44 Private Sub Class_Terminate()
45 On Error Resume Next
46 If mlTimer <> 0 Then CloseHandle mlTimer
47 End Sub
48
49 Public Sub Wait(MilliSeconds As Long)
50 On Error GoTo ErrHandler
51 Dim ft As FILETIME
52 Dim lBusy As Long
53 Dim lRet As Long
54 Dim dblDelay As Double
55 Dim dblDelayLow As Double
56
57 mlTimer = CreateWaitableTimer(0, True, App.EXEName & "Timer" & Format$(Now(), "NNSS"))
58
59 If Err.LastDllError <> ERROR_ALREADY_EXISTS Then
60 ft.dwLowDateTime = -1
61 ft.dwHighDateTime = -1
62 lRet = SetWaitableTimer(mlTimer, ft, 0, 0, 0, 0)
63 End If
64
65 dblDelay = CDbl(MilliSeconds) * 10000#
66
67 ft.dwHighDateTime = -CLng(dblDelay / UNITS) - 1
68 dblDelayLow = -UNITS * (dblDelay / UNITS - Fix(CStr(dblDelay / UNITS)))
69
70 If dblDelayLow < MAX_LONG Then dblDelayLow = UNITS + dblDelayLow
71
72 ft.dwLowDateTime = CLng(dblDelayLow)
73 lRet = SetWaitableTimer(mlTimer, ft, 0, 0, 0, False)
74
75 Do
76 lBusy = MsgWaitForMultipleObjects(1, mlTimer, False, INFINITE, QS_ALLINPUT&)
77 DoEvents
78 Loop Until lBusy = WAIT_OBJECT_0
79
80
81 CloseHandle mlTimer
82 mlTimer = 0
83 Exit Sub
84
85 ErrHandler:
86 Err.Raise Err.Number, Err.Source, "[clsWaitableTimer.Wait]" & Err.Description
87 End Sub
88
89 'FORM中代码
90
91 Private Sub cmdWaitTimer_Click()
92 Dim objTimer As clsWaitableTimer
93 Set objTimer = New clsWaitableTimer
94
95 cmdWaitTimer.Enabled = False
96 objTimer.Wait 5000 '5 秒
97 cmdWaitTimer.Enabled = True
98 Set objTimer = Nothing
99 End Sub
100
101