API Timers in VBA - How to make safe

Pointer-Safe and 64-Bit declarations for the Windows Timer API in VBA
As promised, here are the 32-Bit and 64-Bit API declarations for the Timer API, using LongLong and the Safe Pointer type:

#If VBA7 And Win64 Then    ' 64 bit Excel under 64-bit windows
                           ' Use LongLong and LongPtr

    Private Declare PtrSafe Function SetTimer Lib "user32" _
                                    (ByVal hwnd As LongPtr, _
                                     ByVal nIDEvent As LongPtr, _
                                     ByVal uElapse As LongLong, _
                                     ByVal lpTimerFunc As LongPtr _
                                     ) As LongLong

    Public Declare PtrSafe Function KillTimer Lib "user32" _
                                    (ByVal hwnd As LongPtr, _
                                     ByVal nIDEvent As LongPtr _
                                     ) As LongLong
    Public TimerID As LongPtr


#ElseIf VBA7 Then     ' 64 bit Excel in all environments 
                      ' Use LongPtr only, LongLong is not available

    Private Declare PtrSafe Function SetTimer Lib "user32" _
                                    (ByVal hwnd As LongPtr, _
                                     ByVal nIDEvent As Long, _
                                     ByVal uElapse As Long, _
                                     ByVal lpTimerFunc As LongPtr) As LongPtr

    Private Declare PtrSafe Function KillTimer Lib "user32" _
                                    (ByVal hwnd As LongPtr, _
                                     ByVal nIDEvent As Long) As Long

    Public TimerID As LongPtr

#Else    ' 32 bit Excel

    Private Declare Function SetTimer Lib "user32" _
                            (ByVal hwnd As Long, _
                             ByVal nIDEvent As Long, _
                             ByVal uElapse As Long, _
                             ByVal lpTimerFunc As Long) As Long

    Public Declare Function KillTimer Lib "user32" _
                            (ByVal hwnd As Long, _
                             ByVal nIDEvent As Long) As Long

    Public TimerID As Long

#End If




' Call the timer as: 
'    SetTimer 0&, 0&, lngMilliseconds, AddressOf TimerProc




#If VBA7 And Win64 Then     ' 64 bit Excel under 64-bit windows  ' Use LongLong and LongPtr
                            ' Note that wMsg is always the WM_TIMER message, which actually fits in a Long

    Public Sub TimerProc(ByVal hwnd As LongPtr, _
                         ByVal wMsg As LongLong, _
                         ByVal idEvent As LongPtr, _
                         ByVal dwTime As LongLong)
    On Error Resume Next

    KillTimer hwnd, idEvent   ' Kill the recurring callback here, if that's what you want to do
                              ' Otherwise, implement a lobal KillTimer call on exit

    ' **** YOUR TIMER PROCESS GOES HERE **** 


    End Sub



#ElseIf VBA7 Then          ' 64 bit Excel in all environments

                        ' Use LongPtr only

    Public Sub TimerProc(ByVal hwnd As LongPtr, _
                         ByVal wMsg As Long, _
                         ByVal idEvent As LongPtr, _
                         ByVal dwTime As Long)
    On Error Resume Next

    KillTimer hwnd, idEvent   ' Kill the recurring callback here, if that's what you want to do
                              ' Otherwise, implement a lobal KillTimer call on exit

    ' **** YOUR TIMER PROCESS GOES HERE **** 


    End Sub


#Else    ' 32 bit Excel

    Public Sub TimerProcInputBox(ByVal hwnd As Long, _
                                 ByVal wMsg As Long, _
                                 ByVal idEvent As Long, _
                                 ByVal dwTime As Long)
    On Error Resume Next

    KillTimer hwnd, idEvent   ' Kill the recurring callback here, if that's what you want to do
                              ' Otherwise, implement a lobal KillTimer call on exit

    ' **** YOUR TIMER PROCESS GOES HERE **** 

    End Sub


#End If


The hwnd parameter is set to zero in the sample code above, and should always will be zero if you’re calling this from VBA instead of associating the call with (say) an InputBox or form.

A fully-worked example of this Timer API, including the use of the hwnd parameter for a window, is available on the Excellerando website:

Using the VBA InputBox for passwords and hiding the user’s keyboard input with asterisks.

Footnote:

This has been published as a separate reply to my explanation of the system errors associated with calling the Timer API without careful error-handling: it’s a separate topic, and StackOverflow will benefit from a separate and searchable answer with the Pointer-Safe and 64-Bit declarations for the Windows Timer API.

There are bad examples of the API declarations out there on the web; and there are very few examples for the common case of VBA7 (which supports the Safe Pointer type) installed on a 32-Bit Windows environment (which doesn’t support the 64-Bit ‘LongLong’ integer).

转自:
https://stackoverflow.com/questions/20269844/api-timers-in-vba-how-to-make-safe

猜你喜欢

转载自blog.csdn.net/rznice/article/details/82869983
今日推荐