Использование объектов Waitable Timer в VBA - ошибка неверного дескриптора - PullRequest
0 голосов
/ 09 июня 2019

Я пытаюсь использовать объекты 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

(но я не думаю, что здесь ошибка ...)

1 Ответ

0 голосов
/ 09 июня 2019

О, проблема в неявном 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 необходимы

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...