В VB6 почему обработка событий останавливается в цикле сна?

У меня есть VB6 ActiveX EXE, который имеет обработчики событий для OCX-управления, который он использует. В функции Terminate ActiveX я должен быть уверен, что все события завершили обработку, прежде чем разрешить завершить завершение. В функции Terminate я добавил следующий код в начале:

While EventsInProgressFlags <> 0
    DoEvents
    Sleep(200)
WEnd

EventsInProgressFlags - это Integer, который я использую для установки событий. Однако я наблюдаю, что когда этот цикл работает, события в процессе никогда не завершаются. Из добавления многих сообщений журнала в события и процедуры завершения я вижу, что обработка событий выполняется, когда вызывается функция Terminate, но даже если я вызываю DoEvents, эти события не выполняются, пока активна функция Terminate , Если я заставляю функцию Terminate выйти из цикла, обработка событий продолжается с того места, где она была остановлена, но, конечно же, имеет ошибки, поскольку Terminate уничтожил компоненты, используемые событиями.

Есть ли способ в моем цикле сна, чтобы завершить код события в завершении выполнения?

================ ОБНОВЛЕНИЕ 11-20-2018 ====================

После некоторых онлайн-исследований я считаю, что лучше понять, почему, но еще нет решения.

Прочитав многопоточность в VB6, я понимаю, что VB6 является однопоточным, поэтому да, моя обработка событий OCX и функция Terminate находятся в одном потоке. Вот почему включение функции Terminate в режим сна не сработало. Поскольку они оба находятся в одной и той же ветке VB6, я также помещаю обработку событий в режим сна. Я задавался вопросом, как моя функция ActiveX Terminate вызывается в середине моего кода обработки событий. Моя теория заключается в том, что, поскольку моя обработка событий делает системные вызовы VB6 при выполнении системного вызова, в дополнение к выполнению системного вызова он также вызывает DoEvents для обслуживания очереди событий Windows. Это делается для того, чтобы сделать интерфейс более отзывчивым. Затем вызов DoEvents обрабатывает входящее событие Windows для завершения вызова ActiveX. Мне было бы интересно, если какой-нибудь VB6-гуру может подтвердить мой вывод здесь.

Таким образом, одним из возможных решений было бы, если бы какой-то способ запретить системе вызывать DoEvents, пока я обрабатываю события OCX. Кто-нибудь знает, как это сделать?

Другим возможным решением является возможность возврата из функции Terminate, поэтому обработка событий может продолжаться, но не отправлять ответ от функции Terminate на узел до тех пор, пока обработка обработки событий не будет завершена. Однако это звучит менее правдоподобно.

Всего 1 ответ


Поэтому, как только я понял, что VB6 является одиночным потоком, я вернулся в отладчик и подтвердил, что когда функция Terminate выполняет стек VB6, показывает, что обработка событий OCX находится далее в стеке, ожидая, пока функция Terminate вернется. Очевидно, что обработка событий, которую я хочу завершить (до выхода Terminate), выполняется в том же потоке. Terminate был «вызван VB6», фактически прерывая обработку событий, и это означает, что единственный способ завершить обработку события - вернуться из команды Terminate. Но возврат из Terminate сигнализирует хосту (из ActiveX EXE), что объект ActiveX завершается, когда это действительно не так. Результатом являются ошибки в обработке событий OCX после возвращения функции Terminate.

То, что я хотел, было способом запретить обработку входящих команд в ActiveX EXE. Это предотвратит выполнение функции Terminate во время обработки события. Я не смог найти способ сделать это.

Поэтому менее элегантное решение, с которым я столкнулся, состояло в том, чтобы добавить глобальный флаг HasTerminated Boolean, который задается подпрограммой Terminate. Затем обработчики ошибок для процедур событий кнопки, которые генерировали ошибку # 91 «Объектная переменная или с заблокированной переменной не установлены», были изменены, чтобы игнорировать ошибку # 91, но только если флаг HasTerminated Boolean имеет значение True. Это означает, что прерывание любой обработки событий вызывает ошибку, но только если ActiveX завершен. Это было приемлемым решением в том, что события OCX не нужно было завершать, так как компонент прекращался. Им просто не нужно было вызывать ошибки. Вот пример обработчика ошибок, который я добавил ко всем процедурам обработки событий.

M_SIGN_CAPTURE_FORM_CLEAR_CLICKED_ERR_HANDLER:
40  If HasTerminated And Err.Number = 91 Then
50      Resume 30 ' Resume at Exit Sub
60  End If

70  ErrBox "ERROR #" & Err.Number & " " & FILE__ _
        & ":m_SignCaptureForm_ClearClicked:" & Erl & Err.Description
80  Resume Next
End Sub

Есть идеи?

10000