我尝试在VBA中使用可等待的定时器对象,因为我想异步调用延迟不到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
我是这样调用的:
'[...]
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来自奇普·皮尔逊。absoluteDueTime
是一个fileTime
变量,在该过程的前面设置为Now +1秒。我要进入即时窗口:
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
(但我不认为这就是错误所在…)
发布于 2019-06-09 22:35:37
哦,问题在于所有东西的隐式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
必须将指针传递给byVal,否则它们会立即被延迟吗?这是正确的吗:
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
https://stackoverflow.com/questions/56515365
复制相似问题