Что делает DoEvents в vb6?

Что делает DoEvents в vb6? Почему я получаю сообщение об ошибке "Недостаточно места в стеке"? Что это значит?

4 ответа

Решение

DoEvents() позволяет обрабатывать другие сообщения Windows.

Причина, по которой вы получаете ошибку нехватки места в стеке, возможно, заключается в том, что DoEvents() позволяет происходить событиям, которые снова вызывают ваш код, который снова вызывает DoEvents() и т. Д. До тех пор, пока пространство стека не отследит адреса возврата для всех этих звонки, закончились.

В общем, я не рекомендую использовать DoEvents() из-за подобных проблем и того факта, что он нарушает общий дизайн Windows, управляемый событиями.

Несколько иной взгляд на DoEvents состоит в том, что он сбрасывает события в очереди событий. Если ваша подпрограмма или функция запускает событие, этот обработчик события становится подпрограммой, которая должна быть запущена, как только ваша подчиненная функция / функция будет завершена. DoEvents говорит, что нужно запускать эту подпрограмму обработчика событий вместо ожидания до конца вашей подпрограммы.

Хотя я по духу согласен с Джонатоном в отношении отказа от использования DoEvents, я бы умерил его высказывание, сказав, что рекомендую использовать его, только если вы точно знаете почему и знаете все последствия изменения порядка очереди событий таким образом. Чаще всего DoEvents указывается, когда вы хотите каким-то образом обновить экран из контекста подпрограммы, прежде чем подпрограмма будет завершена.

Примером этого является использование элемента управления ProgressBar. Предположим, что вы перебираете несколько тысяч записей и хотите предоставить пользователю обратную связь о том, как далеко вы продвинулись, обновив индикатор выполнения. Вы можете прерывать цикл каждые сто записей и изменять значение в элементе управления ProgressBar. Однако (если вы не сделаете что-то с этим), вы не увидите изменения на экране до тех пор, пока не будет запущен обработчик события изменения индикатора выполнения, и этот обработчик не запустится, пока ваша подпрограмма не будет выполнена. Он просто будет помещен в очередь событий. Чтобы принудительно запустить событие изменения, приостанавливая работу вашего сабвуфера, нужно вызвать DoEvents. Это удалит все существующие события из очереди - в этом случае событие изменения вашего индикатора выполнения - и обновит элемент управления индикатором на экране.

Теперь "вне стекового пространства" в основном означает, что вы попали в бесконечный цикл вызовов функций. Самый простой способ вызвать это:

Public sub MySub()
    MySub
End Sub

А затем позвоните MySub откуда-то. Вы получите ошибку пространства вне стека. Если вы посмотрите на стек вызовов, вы увидите очень длинную линию вызовов на MySub.

Хорошо известный реальный пример этого случился бы в более старых версиях VB:

Public Sub TextBoxArray_LostFocus(index as Integer)
    If TextBoxArray(index) = "" Then
        TextBoxArray(index).SetFocus
        MsgBox "Please enter a value"
    End If
End Sub

В этой ситуации предполагается наличие двух членов массива элемента управления TextBox с именем TextBoxArray. Теперь, если пользователь начинает с первого (индекс 0) и переходит ко второму (индекс 1), событие LostFocus индекса 0 сработает. Тем не менее, VB также внутренне установит фокус на поле индекса 1. Затем код установит фокус обратно на индекс 0, запустив событие индекса 1 LostFocus! Вы попали в петлю. Они исправили это в VB5 или 6, ожидая установки фокуса, пока не завершилось выполнение события LostFocus.

Я хотел бы уточнить ответ Джонатона в том, что он прокачивает этот цикл сообщений VB и позволяет среде выполнения VB обрабатывать сообщения Windows, что противоположно режиму Sleep, который позволяет Windows обрабатывать свои события (не обязательно в мире многоядерных процессоров и настоящих многозадачных ОС). но когда был написан VB6, Windows 9x была доминирующей ОС, и жесткий цикл, в котором были только DoEvents, увеличил бы загрузку процессора до 100%). Так что видя такие вещи, как

While fDoneFile = False
    DoEvents
    Sleep 55
Wend

была общая картина во всем мире VB6.

Как уже говорилось, DoEvents позволяет запускать другие события в вашем приложении. Вот пример того, как вы можете использовать DoEvents без проблемы "Out of stack space". Это гарантирует, что вы не запускаете код несколько раз, используя логическое значение, чтобы указать, что код работает.

Sub Example()
    'Create static variable to indicate the sub is running.
    Static isRunning As Boolean
    'Exit the sub if isRunning
    If isRunning Then Exit Sub
    'Indicate sub is running
    isRunning = True
    'Sub does stuff
    DoEvents
    'Ends up calling sub again
    Example 'Added just to prove via testing.
    'Indicate sub is no longer runningrunning
    isRunning = False
End Sub
Другие вопросы по тегам