При разработке и адаптации автоматизированных рабочих мест (АРМ) на платформе 1С:Предприятие 8.3 (в конфигурациях на обычных формах, таких как УПП или отраслевые решения вроде «Мясокомбинат») разработчики нередко сталкиваются с неприятным эффектом: при однократном считывании штрихкода сканером процедура ВнешнееСобытие выполняется два раза подряд. В результате данные могут задваиваться, полутуши или товары регистрироваться дважды, либо интерфейс блокируется ошибками повторного поиска.
Разберем по шагам, почему возникает эта проблема, имеет ли к ней отношение релиз платформы, какую роль играет переменная мВнешнееСобытиеОбработано и как гарантированно устранить двойное срабатывание.
Рассмотрим фрагмент кода, на который часто падает подозрение разработчиков:
Процедура ЗавершитьОбработкуВнешнегоСобытия(Источник, Событие, Данные) Экспорт
Оборудование = ПолучитьТО();
ТО = Оборудование.Найти(Источник, "ИмяИсточникаВнешнегоСобытия");
Если ТО <> Неопределено Тогда
Обработка = ТО.Обработка;
Объект = ТО.Объект;
Обработка.СобытиеОбработано(Объект, мВнешнееСобытиеОбработано);
КонецЕсли;
мВнешнееСобытиеОбработано = Ложь;
КонецПроцедуры
Выясним причину поведения: флаг мВнешнееСобытиеОбработано = Ложь; не заставляет платформу вызывать событие повторно. Платформа 1С:Предприятие не управляет циклом опроса на основе этого флага. Переменная мВнешнееСобытиеОбработано является внутренней переменной конфигурации (в модуле ТОСервер) и передается обратно в метод внешней компоненты СобытиеОбработано() исключительно для информирования драйвера. Сама платформа 1С лишь пассивно реагирует на системные оповещения ExternalEvent, которые шлет драйвер оборудования. Смена релиза платформы также не решит проблему, так как источник задвоения лежит на стыке физического оборудования, настроек драйвера и архитектуры подключения формы.
Как показывает практика, ключевая разница кроется в режиме подключения сканера штрихкодов. Если на стабильно работающих рабочих местах сканеры подключены через эмуляцию виртуального COM-порта (VCP), а на проблемном АРМ устройство работает в режиме эмуляции клавиатуры (HID Keyboard Wedge), то двойное событие обусловлено особенностями клавиатурного перехвата:
CR (байт 13) и перевод строки LF (байт 10). Если в настройках торгового оборудования 1С в качестве суффикса указан только один символ (например, 13), клавиатурный драйвер отсекает первую часть посылки и генерирует событие, а оставшийся символ 10 расценивает как следующую посылку по таймауту, порождая второе внешнее событие.Это наиболее надежный и рекомендуемый способ интеграции торгового оборудования в 1С. Проанализируем порядок действий:
COM3).COM3, укажите скорость и корректный суффикс (обычно 13).В режиме COM-порта поток данных строго изолирован от клавиатурного буфера, и внешняя компонента гарантированно формирует ровно один вызов ВнешнееСобытие на каждое физическое сканирование.
Если перевести сканер в режим COM-порта невозможно (например, из-за ограничений рабочего места или прав доступа), выполним точную настройку клавиатурного драйвера:
CR (символ с кодом 13). Полностью отключите суффикс LF (код 10).#13.Посмотрим на ситуацию со стороны кода формы АРМ. Когда логику работы с оборудованием выносят из типового общего модуля ТОСервер непосредственно в модуль формы, часто допускают ошибку двойного подключения. Если сканер был подключен глобально при старте сеанса, а затем форма выполнила повторное подключение того же устройства, драйвер может зарегистрировать два обработчика.
Убедимся, что при открытии формы не происходит дублирующего подключения, а при закрытии формы обязательно вызывается процедура отключения оборудования. Также в самом начале процедуры ВнешнееСобытие рекомендуется проверить доступность формы:
Если Не ВводДоступен() Тогда
Возврат;
КонецЕсли;
Для гарантированной защиты от дублей на программном уровне (в случае аппаратного дребезга или сетевых задержек) реализуем программную фильтрацию повторных событий (Debounce) по времени и значению штрихкода:
Перем мПоследнийШтрихкод Экспорт;
Перем мВремяПоследнегоСканирования Экспорт;
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Проверяем тип события
Если Не (Событие = "BarCodeData" Или Событие = "Штрихкод") Тогда
Возврат;
КонецЕсли;
ТекущееВремя = ТекущаяДата();
// Отсекаем дублирование: один и тот же ШК, пришедший менее чем через 2 секунды
Если Данные = мПоследнийШтрихкод И (ТекущееВремя - мВремяПоследнегоСканирования) < 2 Тогда
Возврат;
КонецЕсли;
мПоследнийШтрихкод = Данные;
мВремяПоследнегоСканирования = ТекущееВремя;
// Выполняем полезную обработку штрихкода
ОбработатьШтрихкодАРМ(Данные);
КонецПроцедуры
Использование программного фильтра позволяет защитить систему от двойной записи данных даже в тех случаях, когда физический сканер отправляет два одинаковых пакета подряд.