Поток выполнения VBA неожиданно прерван - PullRequest
0 голосов
/ 02 июля 2018

Контекст проблемы

Я разрабатываю новую функцию для HMI с использованием Factory Talk View Studio 7.00.00 (CPR 9 SR 6) и VBA 6.5 .
У меня есть два дисплея: ma1_header и ma2_header и, как многие из вас знают, в Factory Talk View Studio (я буду называть его FTV для краткости отныне) каждый Дисплей имеет выделенный DisplayCode . Код отображения может рассматриваться как код VBA за файлом Excel, который остается открытым до тех пор, пока его файл Excel. С этой точки зрения код VBA, привязанный к отображению в FTV, имеет то же поведение, что и проект VBA в Excel, поэтому он закрывается, когда графический дисплей закрывается пользователем или из кода.

enter image description here

Другим важным моментом для понимания проблемы является то, что когда общий дисплей в FTV, называемый A, открывается в Режим замены хотя бы с одним пикселем, который перекрывает другой дисплей B, дисплей B закрывается с помощью его код VBA. Помните, что ma1_header и ma2_header всегда открыты в режиме замены.

Описание проблемы

Тем не менее, теперь я собираюсь описать проблему, которую я обнаружил.
Код VBA, привязанный к ma1_header и ma2_header, в основном одинаков (различия указаны в следующей схеме), и он выполняет некоторые действия инициализации при запуске дисплея, а после него запускает процедуру, называемую ScheduleCheck . Эта процедура обновляет некоторые компоненты пользовательского интерфейса и оценивает некоторые условия, чтобы определить, пора ли показывать ma2_header (ma1_header, если код выполняется за ma2_header), а затем вызывает себя.

enter image description here

Команда, которая открывает дисплей, не выполняется непосредственно из VBA, она выполняется асинхронно вне VBA. Фактически VBA для некоторых действий, таких как: «Показать отображение», «Задать значения тегов» и т. Д., Может использовать библиотеку, которая позволяет ему сообщать службе FTV (которая также может использоваться с инструментом командной строки) для выполнения список этих действий (1 или более команд, переданных одновременно).
Когда пользователь запускает клиент FTV, сначала отображается ma1_header с некоторыми другими дисплеями, составляющими пользовательский интерфейс.
В ma1_header, когда условия открытия для ma2_header удовлетворены и он открыт, проблема возникает. Давайте теперь приступим к пошаговому описанию состояния VBA, чтобы как можно яснее разобраться в проблеме:

  1. В ma1_header условия открытия выполняются, и выполняется асинхронная команда, которая показывает ma2_header. Обратите внимание, что на данный момент ma1_header vba все еще открыт.
  2. Когда ma2_header начинает открывать код, он выполняется без проблем до процедуры ожидания. Процедура ожидания записывается следующим образом:

    Public Declare Function GetTickCount Lib "kernel32" () As Long
    
    Public Sub wait(lMillSec As Long)
        Dim lT2 As Long
        Dim lT1 As Long
    
    On Error GoTo errHandle
        Const strMethod = "wait"
        MsgBox "wait - 1"
        lT1 = GetTickCount
        lT2 = lT1
        While lT2 - lT1 < lMillSec
            lT2 = GetTickCount
            DoEvents
        Wend
    errHandle:
        If Err.Number Then
            LogDiagnosticsMessage "VBA: Display " & Me.Name & " in Method " & strMethod
            Err.Clear
        End If
    End Sub
    
  3. Выполнение процедуры ожидания продолжается без каких-либо проблем до тех пор, пока команда DoEvents в 18-ых строках. Когда DoEvents выполняется, у ma1_header есть время, чтобы окончательно закрыть себя (даже его код vba), тогда поток vba в ma2_header, кажется, останавливается здесь без какой-либо ошибки. Из-за этого ScheduleCheck не может вспомнить себя.

Гадкий раствор 1

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

Когда ma1_header открыт, открытие ma2_header приведет к закрытию ma1_header, которое, как я объяснял ранее, завершается только при выполнении DoEvents. Я попытался передать этот новый список команд инструменту FTW, когда нужно показать ma2_header:

##New##
Abort MA2_HEADER;
Pause 1;
Display MA1_HEADER /TRRU;

##Old##
Display MA1_HEADER /TRRU;

При новом подходе я закрываю ma2_header, затем жду (в инструменте FTV, а не в VBA) 1 секунду с командой «Пауза 1;» затем я открываю ma1_header, когда я уверен, что ma1_heder закрыт благодаря команде pause. Таким образом, ma2_heder периодически выполняет процедуру ScheduleCheck без странного прерывания выполнения.

Я не знаю, почему это решает мою проблему, поэтому я хотел бы понять, почему это работает и что является причиной этой проблемы, чтобы найти лучшее решение.

Гадкий раствор 2

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

  1. Я создал следующий новый тег на сервере тегов FTV

enter image description here

  1. Я создал следующее новое событие на FTV:

enter image description here

  1. Я добавил отображение строки, содержащее новый тег Tick в ma1_header и в ma2_header

    1. Теперь в VBA я могу использовать событие Change этого отображения строки для выполнения того же кода, содержащегося в ScheduleCheck (очевидно, без ожидания с циклом DoEvents) каждый раз, когда изменяется отображение этой строки ( каждую секунду).

Буду очень признателен за любые разъяснения по поводу проблемы или лучшее решение.

...