Почему при сканировании штрихкода в 1С внешнее событие срабатывает дважды и как это исправить?

Программист 1С v8.3 (Обычные формы) Управленческий учет Промышленность, строительство и АПК
← На главную

При разработке и адаптации автоматизированных рабочих мест (АРМ) на платформе 1С:Предприятие 8.3 (в конфигурациях на обычных формах, таких как УПП или отраслевые решения вроде «Мясокомбинат») разработчики нередко сталкиваются с неприятным эффектом: при однократном считывании штрихкода сканером процедура ВнешнееСобытие выполняется два раза подряд. В результате данные могут задваиваться, полутуши или товары регистрироваться дважды, либо интерфейс блокируется ошибками повторного поиска.

Разберем по шагам, почему возникает эта проблема, имеет ли к ней отношение релиз платформы, какую роль играет переменная мВнешнееСобытиеОбработано и как гарантированно устранить двойное срабатывание.

Анализ кода завершения обработки и влияние платформы

Рассмотрим фрагмент кода, на который часто падает подозрение разработчиков:


Процедура ЗавершитьОбработкуВнешнегоСобытия(Источник, Событие, Данные) Экспорт
    Оборудование = ПолучитьТО();
    ТО = Оборудование.Найти(Источник, "ИмяИсточникаВнешнегоСобытия");
    Если ТО <> Неопределено Тогда
        Обработка    = ТО.Обработка;
        Объект       = ТО.Объект;
        Обработка.СобытиеОбработано(Объект, мВнешнееСобытиеОбработано);
    КонецЕсли;
    мВнешнееСобытиеОбработано = Ложь;
КонецПроцедуры

Выясним причину поведения: флаг мВнешнееСобытиеОбработано = Ложь; не заставляет платформу вызывать событие повторно. Платформа 1С:Предприятие не управляет циклом опроса на основе этого флага. Переменная мВнешнееСобытиеОбработано является внутренней переменной конфигурации (в модуле ТОСервер) и передается обратно в метод внешней компоненты СобытиеОбработано() исключительно для информирования драйвера. Сама платформа 1С лишь пассивно реагирует на системные оповещения ExternalEvent, которые шлет драйвер оборудования. Смена релиза платформы также не решит проблему, так как источник задвоения лежит на стыке физического оборудования, настроек драйвера и архитектуры подключения формы.

Основная причина: режим работы сканера (Клавиатурный клин против COM-порта)

Как показывает практика, ключевая разница кроется в режиме подключения сканера штрихкодов. Если на стабильно работающих рабочих местах сканеры подключены через эмуляцию виртуального COM-порта (VCP), а на проблемном АРМ устройство работает в режиме эмуляции клавиатуры (HID Keyboard Wedge), то двойное событие обусловлено особенностями клавиатурного перехвата:

  1. Несоответствие суффиксов: Большинство сканеров в режиме клавиатуры по умолчанию передают после штрихкода два управляющих символа: перевод каретки CR (байт 13) и перевод строки LF (байт 10). Если в настройках торгового оборудования 1С в качестве суффикса указан только один символ (например, 13), клавиатурный драйвер отсекает первую часть посылки и генерирует событие, а оставшийся символ 10 расценивает как следующую посылку по таймауту, порождая второе внешнее событие.
  2. Низкая чувствительность (таймаут между символами): В клавиатурном режиме символы штрихкода приходят поочередно. Если в параметрах драйвера установлен слишком малый таймаут чувствительности, драйвер может разделить один поток символов на две независимые пачки.
  3. Конфликт клавиатурного хука и фокуса формы: При эмуляции клавиатуры штрихкод может одновременно попадать в активное поле формы как ввод текста и перехватываться низкоуровневым хуком драйвера, вызывая параллельную обработку.

Способ 1. Перевод сканера в режим эмуляции виртуального COM-порта

Это наиболее надежный и рекомендуемый способ интеграции торгового оборудования в 1С. Проанализируем порядок действий:

  1. Откройте сервисную инструкцию (руководство пользователя) к конкретной модели сканера.
  2. Считайте управляющий штрихкод для перевода в режим USB Virtual COM (или USB Serial Emulation).
  3. Установите виртуальный COM-драйвер от производителя сканера в операционную систему. В диспетчере устройств появится виртуальный последовательный порт (например, COM3).
  4. В 1С в настройках торгового оборудования измените тип подключения сканера с клавиатурного на порт COM3, укажите скорость и корректный суффикс (обычно 13).

В режиме COM-порта поток данных строго изолирован от клавиатурного буфера, и внешняя компонента гарантированно формирует ровно один вызов ВнешнееСобытие на каждое физическое сканирование.

Способ 2. Корректировка параметров клавиатурного режима

Если перевести сканер в режим COM-порта невозможно (например, из-за ограничений рабочего места или прав доступа), выполним точную настройку клавиатурного драйвера:

  1. С помощью инструкции производителя настройте сканер так, чтобы он посылал строго один суффикс — CR (символ с кодом 13). Полностью отключите суффикс LF (код 10).
  2. В настройках торгового оборудования 1С задайте суффикс #13.
  3. Увеличьте значение параметра Чувствительность в настройках драйвера в 1С (оптимальное значение обычно находится в пределах от 30 до 50 мс), чтобы исключить разрыв строки штрихкода на две части.

Способ 3. Проверка жизненного цикла подключения и программный антидребезг

Посмотрим на ситуацию со стороны кода формы АРМ. Когда логику работы с оборудованием выносят из типового общего модуля ТОСервер непосредственно в модуль формы, часто допускают ошибку двойного подключения. Если сканер был подключен глобально при старте сеанса, а затем форма выполнила повторное подключение того же устройства, драйвер может зарегистрировать два обработчика.

Убедимся, что при открытии формы не происходит дублирующего подключения, а при закрытии формы обязательно вызывается процедура отключения оборудования. Также в самом начале процедуры ВнешнееСобытие рекомендуется проверить доступность формы:


Если Не ВводДоступен() Тогда
    Возврат;
КонецЕсли;

Для гарантированной защиты от дублей на программном уровне (в случае аппаратного дребезга или сетевых задержек) реализуем программную фильтрацию повторных событий (Debounce) по времени и значению штрихкода:


Перем мПоследнийШтрихкод Экспорт;
Перем мВремяПоследнегоСканирования Экспорт;

Процедура ВнешнееСобытие(Источник, Событие, Данные)
    
    // Проверяем тип события
    Если Не (Событие = "BarCodeData" Или Событие = "Штрихкод") Тогда
        Возврат;
    КонецЕсли;
    
    ТекущееВремя = ТекущаяДата();
    
    // Отсекаем дублирование: один и тот же ШК, пришедший менее чем через 2 секунды
    Если Данные = мПоследнийШтрихкод И (ТекущееВремя - мВремяПоследнегоСканирования) < 2 Тогда
        Возврат;
    КонецЕсли;
    
    мПоследнийШтрихкод = Данные;
    мВремяПоследнегоСканирования = ТекущееВремя;
    
    // Выполняем полезную обработку штрихкода
    ОбработатьШтрихкодАРМ(Данные);
    
КонецПроцедуры

Использование программного фильтра позволяет защитить систему от двойной записи данных даже в тех случаях, когда физический сканер отправляет два одинаковых пакета подряд.

← На главную