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

Программист 1С v8.3 (Управляемые формы) Торговля и дистрибуция
← На главную

При разработке торговых решений в среде 1С:Предприятие 8 программисты часто сталкиваются со спецификой работы торгового оборудования. Одной из наиболее распространенных задач является подключение сканера штрихкодов. На первый взгляд, алгоритм работы прост: сканер считывает штрихкод, драйвер генерирует внешнее событие, платформа 1С перехватывает его и передает в активную форму. Однако на практике разработчики самописных конфигураций на управляемых формах нередко сталкиваются со странным поведением оборудования. При открытии любого вспомогательного окна (например, формы ввода дисконтной карты или поиска товара) сканер штрихкодов внезапно «засыпает». Он издает звуковой сигнал успешного сканирования, но данные в 1С больше не поступают — ни в открытую форму, ни в основную форму документа после ее закрытия. Единственным выходом кажется перезапуск сеанса 1С.

В рамках этой статьи мы подробно разберем, почему возникает эта проблема, проанализируем физику работы драйвера Атол и рассмотрим три практических сценария решения этой задачи.

Анализ исходной ситуации: как воспроизводится проблема

Рассмотрим классический пример реализации рабочего места кассира или менеджера по продажам. В форме документа «Реализация» настроен прием данных от сканера штрихкодов через предопределенную процедуру ВнешнееСобытие. Для интеграции используется популярный драйвер торгового оборудования от компании Атол.

Процедура обработки события в форме документа выглядит следующим образом:


&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
    Если ВводДоступен() Тогда
        Если Источник = "BarCodeScaner" Тогда
            ПараметрыОповещения = Новый Структура;
            ПараметрыОповещения.Вставить("ПроцессОтладки", Ложь);
            ПараметрыОповещения.Вставить("ТекстПриЗавершении", "Выполнен метод Атола: DeleteEvent");
            
            Оповещение = Новый ОписаниеОповещения("ЗавершениеМетодаАтол", ЭтотОбъект, ПараметрыОповещения);
            
            глСканерШк.НачатьВызовDeleteEvent(Оповещение);
            глСканерШк.НачатьУстановкуDataEventEnabled(, 1);
            
            ШтрихКод = СокрЛП(Данные);
            // Далее следует логика поиска товара по штрихкоду и добавления в табличную часть
        КонецЕсли;
    КонецЕсли;
КонецПроцедуры

Бизнес-требования меняются, и появляется задача реализовать работу с дисконтными картами. Для этого создается справочник «Дисконтные карты». Чтобы кассир мог быстро найти карту или ввести ее вручную, создается небольшая вспомогательная форма ввода штрихкода. На ней располагается всего одно поле — Штрихкод.

Из формы документа данное окно открывается в блокирующем режиме с помощью следующего кода:


&НаКлиенте
Процедура ВводДкПоШтрихкоду(Команда)
    ДопПараметры = Новый Структура("ШтрихкодЧего", "ДисконтнаяКарта");
    Оповещение = Новый ОписаниеОповещения("ВводПоШтрихкодуЗавершение", ЭтотОбъект, ДопПараметры);
    ОткрытьФорму(
        "Справочник.ДисконтныеКарты.Форма.ФормаВводШтрихкода", 
        , 
        ЭтотОбъект, 
        , 
        , 
        , 
        Оповещение, 
        РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
    );    
КонецПроцедуры

Если пользователь вводит штрихкод дисконтной карты вручную с клавиатуры, система отрабатывает штатно. Но если при открытом окне ввода дисконтной карты попытаться отсканировать штрихкод физическим сканером, происходит сбой: в поле ввода ничего не появляется. Самое критичное — после закрытия этого окна сканер полностью перестает реагировать на любые действия в основном документе «Реализация». В процедуру ВнешнееСобытие формы документа управление больше не передается.

Выясняем причину: физика работы драйвера Атол

Чтобы понять, почему ломается работа торгового оборудования, проанализируем архитектуру драйвера Атол и механизм взаимодействия платформы 1С:Предприятие с внешними событиями операционной системы.

Работа большинства драйверов Атол базируется на трех китах: свойстве включения генерации событий, механизме автоматического отключения и методе очистки очереди буфера.

  1. Свойство DataEventEnabled (Посылка данных): Когда это свойство имеет значение Истина (или 1), драйвер готов транслировать считанные аппаратной частью штрихкоды в операционную систему, откуда платформа 1С забирает их в виде внешних событий.
  2. Свойство AutoDisable (Автовыключение): По умолчанию в драйверах Атол включена функция автоматического отключения генерации событий. Как только сканер считывает штрихкод, драйвер передает событие в систему и автоматически сбрасывает значение DataEventEnabled в Ложь (0). Это сделано для того, чтобы защитить систему от лавинообразного накопления необработанных штрихкодов. Пока текущее событие не будет обработано и подтверждено кодом 1С, новые штрихкоды генерировать события не будут.
  3. Метод DeleteEvent (Удаление события): Этот метод очищает текущее событие из буфера драйвера, сигнализируя ему, что данные успешно приняты платформой.

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

  1. Вы открываете модальное или блокирующее окно ввода штрихкода дисконтной карты. Активным становится окно этой вспомогательной формы.
  2. Вы производите сканирование штрихкода дисконтной карты.
  3. Драйвер Атол считывает данные, помещает их в буфер, посылает сигнал операционной системе и, согласно логике AutoDisable, устанавливает свойство DataEventEnabled в значение 0 (выключено).
  4. Платформа 1С:Предприятие перехватывает сигнал ОС и пытается передать внешнее событие активной в данный момент форме справочника.
  5. Платформа проверяет свойства активной формы справочника и видит, что у нее отсутствует обработчик ВнешнееСобытие. Событие просто игнорируется платформой и «тонет».
  6. Поскольку обработчик события не запустился, в коде 1С не вызываются обязательные методы очистки очереди драйвера: DeleteEvent и повторная установка DataEventEnabled = 1.
  7. Драйвер Атол навсегда зависает в заблокированном состоянии. Все последующие сканирования физически отрабатывают (сканер пикает), но данные складываются во внутренний буфер драйвера (растет внутренний счетчик DataCount) и никогда больше не отправляются в 1С, так как генерация событий заблокирована.

Для восстановления работы драйвера требуется деинициализировать и заново инициализировать объект драйвера, что в рамках простой логики формы происходит только при полной перезагрузке клиентского сеанса 1С.

Вариант решения №1: Добавление обработчика во вспомогательную форму и контроль доступности ввода

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

Однако здесь возникает другая проблема: особенности маршрутизации внешних событий в 1С. Платформа устроена так, что при генерации внешнего события оно последовательно передается всем открытым формам, у которых назначен этот обработчик. Когда во вспомогательной форме срабатывает сканирование, форма обрабатывает штрихкод дисконтной карты и закрывается. Но в этот же момент событие летит в форму документа «Реализация», которая тут же пытается найти товар по штрихкоду дисконтной карты и выдает ошибку.

Чтобы обойти это поведение, проанализируем работу метода ВводДоступен(). Если вспомогательная форма закрывается непосредственно внутри обработчика внешнего события, то на момент передачи события форме документа метод ВводДоступен() для документа вернет Истина, и логика поиска товара выполнится.

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


&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
    Если Источник = "BarCodeScaner" Тогда
        // Очищаем буфер драйвера Атол, чтобы он не завис
        глСканерШк.НачатьВызовDeleteEvent();
        глСканерШк.НачатьУстановкуDataEventEnabled(, 1);
        
        ШтрихкодКарты = СокрЛП(Данные);
        
        // Вместо моментального Закрыть() используем оповещение или обработчик ожидания,
        // либо передаем данные владельцу формы и закрываем окно асинхронно.
        ПодключитьОбработчикОжидания("АсинхронноеЗакрытиеФормы", 0.1, Истина);
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура АсинхронноеЗакрытиеФормы()
    Закрыть(ШтрихкодКарты);
КонецПроцедуры

При таком подходе на момент, когда событие будет передаваться форме документа-владельца, вспомогательная форма еще будет активна и заблокирует ввод для основного документа. Метод ВводДоступен() в форме документа вернет Ложь, и обработка штрихкода в документе будет проигнорирована.

Вариант решения №2: Временное программное отключение устройства (Рекомендуемый способ)

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

Более надежный и профессиональный подход — временно деактивировать устройство при потере фокуса основной формой или при открытии модальных окон. Рассмотрим, как это реализовать.

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

Модифицируем код открытия формы в документе «Реализация»:


&НаКлиенте
Процедура ВводДкПоШтрихкоду(Команда)
    // Шаг 1. Отключаем сканер штрихкодов перед открытием формы
    глСканерШк.НачатьУстановкуDeviceEnabled(, 0);
    
    ДопПараметры = Новый Структура("ШтрихкодЧего", "ДисконтнаяКарта");
    Оповещение = Новый ОписаниеОповещения("ВводПоШтрихкодуЗавершение", ЭтотОбъект, ДопПараметры);
    
    ОткрытьФорму(
        "Справочник.ДисконтныеКарты.Форма.ФормаВводШтрихкода", 
        , 
        ЭтотОбъект, 
        , 
        , 
        , 
        Оповещение, 
        РежимОткрытияОкнаФормы.БлокироватьОкноВладельца
    );    
КонецПроцедуры

&НаКлиенте
Процедура ВводПоШтрихкодуЗавершение(Результат, ДополнительныеПараметры) Экспорт
    // Шаг 2. Включаем сканер обратно при закрытии вспомогательной формы
    глСканерШк.НачатьУстановкуDeviceEnabled(, 1);
    
    Если ЗначениеЗаполнено(Результат) Тогда
        // Обработка полученного штрихкода дисконтной карты
    КонецЕсли;
КонецПроцедуры

Данный подход является наиболее чистым с точки зрения архитектуры программирования 1С. Он исключает необходимость прописывать логику торгового оборудования во всех вспомогательных формах вашей конфигурации.

Вариант решения №3: Архитектурный подход на основе БПО (Библиотеки подключаемого оборудования)

Если вы планируете развивать вашу самописную конфигурацию и добавлять новые типы оборудования (фискальные регистраторы, терминалы сбора данных, весы), настоятельно рекомендуем изучить и внедрить стандарты БПО от фирмы 1С.

В БПО данная проблема решена системно за счет следующих механизмов:

Использование одного из предложенных вариантов позволит вам раз и навсегда решить проблему зависания торгового оборудования Атол при открытии дополнительных окон и обеспечить стабильную и бесперебойную работу пользователей в вашей системе.

← На главную