Я пытаюсь использовать объекты Waitable Timer в 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 (struct)
'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 исходит от Чипа Пирсона. absoluteDueTime
- это переменная fileTime
, для которой установлено Сейчас + 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
(но я не думаю, что здесь ошибка ...)