В VB6 почему обработка событий останавливается в цикле ожидания? - PullRequest
0 голосов
/ 17 ноября 2018

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

While EventsInProgressFlags <> 0
    DoEvents
    Sleep(200)
WEnd

EventsInProgressFlags - это целое число, которое я использую, чтобы указать, какие события происходят.Однако, что я наблюдаю, так это то, что когда этот цикл запускает происходящие события, они никогда не завершаются.Добавив множество сообщений журнала к событиям и подпрограмме завершения, я вижу, что обработка события выполняется при вызове функции 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 Ответ

0 голосов
/ 22 ноября 2018

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

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

Так что менее изящное решение, которое я придумал, это добавить глобальный логический флаг HasTeridity, который устанавливается подпрограммой Terminate.Затем обработчики ошибок для подпрограмм события кнопки, которые генерировали ошибку # 91 «Переменная объекта или С переменной блока не установлена» , были изменены, чтобы игнорировать ошибку # 91, но только если HasTermination Booleanфлаг это правда.То, что это делает, прерывает любую обработку события, которая вызывает ошибку, но только если 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...