在VBA中使用Waiting Timer对象-无效的句柄错误

时间:2019-06-09 14:21:34

标签: excel vba winapi timer

我正在尝试在VBA中使用Waiting Timer对象,因为我想以小于1秒的延迟异步调用某些东西(因此没有Application.OnTime),并且带有参数(所以没有SetTimer API)

我还没有发现有人在其他任何地方尝试此操作,因此我必须从头开始做所有事情,但是我认为这应该可行。以下是API声明:

Public Declare Function CreateWaitableTimer Lib "kernel32" Alias "CreateWaitableTimerA" ( _
                        ByVal lpTimerAttributes As Long, _
                        ByVal manualReset As Boolean, _
                        ByVal lpTimerName As Long) As Long
'The A meaning Ansi not Unicode https://jeffpar.github.io/kbarchive/kb/145/Q145727/

Public Declare Function SetWaitableTimer Lib "kernel32" ( _
                        timerHandle As Long, _
                        lpDueTime As fileTime, _
                        lPeriod As Long, _
                        pfnCompletionRoutine As Long, _
                        lpArgToCompletionRoutine As Long, _
                        fResume As Boolean) As Boolean

哪个引用了一个fileTime(结构)

'see https://social.msdn.microsoft.com/Forums/sqlserver/en-US/a28a32c6-df4e-41b9-94ce-6260812dd92f/problem-trying-to-run-32-bit-vba-program-on-a-64-bit-machine?forum=exceldev
Public Type fileTime
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

我正在这样调用API:

'[...]

args = 1234 'public args As Long so it doesn't go out of scope while the timer is waiting

Dim timerHandle As Long
timerHandle = CreateWaitableTimer(0, False, 0)

Debug.Print GetSystemErrorMessageText(Err.LastDllError)

If Not SetWaitableTimer(timerHandle, absoluteDueTime, 0, AddressOf TimerCallbacks.pointerProc, VarPtr(args), False) Then
    Debug.Print "Error: "; GetSystemErrorMessageText(Err.LastDllError)
End If

GetSystemErrorMessageText来自Chip Pearson。 absoluteDueTime是一个fileTime变量,在该过程中被设置为 Now + 1 seconds 。 我进入即时窗口:

  

0-操作成功完成。

     

错误:6-手柄无效。

意味着CreateWaitableTimer似乎有效,但SetWaitableTimer无效。

FWIW TimerCallbacks.pointerProc如下:

Public Sub pointerProc(ByVal argPtr As Long, ByVal timerLowValue As Long, ByVal timerHighValue As Long)
    Debug.Print "pointerProc called"; Time
End Sub

(但我不认为这是错误所在...)

1 个答案:

答案 0 :(得分:0)

哦,问题出在所有内容的隐式byRef上:

Public Declare Function SetWaitableTimer Lib "kernel32" ( _
                        timerHandle As Long, _
                        lpDueTime As fileTime, _
                        lPeriod As Long, _
                        pfnCompletionRoutine As Long, _
                        lpArgToCompletionRoutine As Long, _
                        fResume As Boolean) As Boolean

指针必须由Val传递,否则它们将立即被引用?这是正确的吗?

Public Declare Function SetWaitableTimer Lib "kernel32" ( _
                        byVal timerHandle As Long, _
                        byRef lpDueTime As fileTime, _
                        byRef lPeriod As Long, _
                        byVal pfnCompletionRoutine As Long, _
                        byVal lpArgToCompletionRoutine As Long, _
                        byRef fResume As Boolean) As Boolean

不确定是否所有byRef都是必需的