При интеграции торгового оборудования в самописные или нетиповые конфигурации 1С разработчики нередко сталкиваются с ситуацией: сканер штрихкода, работающий через виртуальный COM-порт и внешнюю компоненту, корректно передает данные ровно один раз, после чего перестает реагировать на считывание. В некоторых случаях внешнее событие прекращает генерироваться после перезапуска сеанса 1С, а для восстановления работоспособности порта приходится перезагружать операционную систему. Разберем детально, почему это происходит и как правильно настроить программное взаимодействие со сканером.
Проанализируем стандартную архитектуру внешних компонент, построенных по стандарту OPOS (например, классическая компонента ScanOPOS или AddIn.Scanner). Согласно спецификации, после каждого успешного считывания штрихкода и генерации внешнего события драйвер автоматически переводит внутреннее свойство разрешения передачи данных в значение 0 (Ложь). Это сделано для того, чтобы защитить очередь сообщений приложения от переполнения, пока платформа 1С занята обработкой предыдущей порции данных.
Если в коде обработчика ВнешнееСобытие не вернуть флаг готовности к приему следующего штрихкода, компонента блокирует дальнейшую отправку сообщений в платформу, хотя сам физический луч сканера может продолжать пикать.
Для возобновления генерации событий необходимо после обработки штрихкода повторно установить свойство DataEventEnabled (в русскоязычном варианте интерфейса драйвера — ПосылкаДанных) в значение 1.
Посмотрим на пример правильной организации процедуры в модуле управляемой формы:
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Событие = "BarCodeValue" Тогда
// Обрабатываем полученный штрихкод
Результат = РаботаСоШтрихкодами.ПолучитьСсылкуНаОбъектПоШтрихкоду(Данные);
Если ЗначениеЗаполнено(Результат) Тогда
ТекущийСотрудник = Результат;
ЗаполнитьДокументыВРаботе();
Иначе
ТекущийСотрудник = Неопределено;
Сообщить("Не удалось идентифицировать штрихкод: " + Данные);
КонецЕсли;
// Очищаем буфер и снова разрешаем передачу данных
Если глСканерШК <> Неопределено Тогда
глСканерШК.ClearInput();
глСканерШК.DataEventEnabled = 1;
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Выясним причину, по которой порт COM намертво блокируется при перезапуске программы и освобождается только перезагрузкой компьютера. Обратим внимание на объявление стандартных обработчиков в модуле управляемого приложения:
Функция ПриНачалеРаботыСистемы()
// ...
КонецФункции
Функция ПриЗавершенииРаботыСистемы()
// ...
КонецФункции
В платформе 1С:Предприятие системные события жизненного цикла сеанса должны объявляться исключительно как Процедура. Если объявить их как Функция, платформа не сможет корректно инициировать их выполнение при выходе из программы. В результате процедура отключения оборудования не вызывается вовсе:
Release() не освобождает логическое устройство в драйвере.Close() не закрывает дескриптор виртуального COM-порта в Windows.Исправим объявление обработчиков в модуле приложения на процедуры:
Процедура ПриНачалеРаботыСистемы()
Если Пользователи.ТребуетсяПодключениеСканераШтрихКодов() Тогда
глСканерШК = ПодключитьСканерШК();
Иначе
глСканерШК = Неопределено;
КонецЕсли;
КонецПроцедуры
Процедура ПриЗавершенииРаботыСистемы()
Если глСканерШК <> Неопределено Тогда
ОтключитьСканерШК();
КонецЕсли;
КонецПроцедуры
Рассмотрим порядок вызовов методов внешней компоненты. В стандарте OPOS монопольный захват оборудования методом Claim() должен обязательно выполняться до перевода свойства DeviceEnabled в единицу. Если попытаться активировать устройство до его монопольного захвата, компонента может перейти в нестабильное состояние.
Пошагово правильная схема инициализации выглядит следующим образом:
ПодключитьВнешнююКомпоненту и новый AddIn.Scanner.Open("СканерШК").Порт, Скорость, БитДанных.Claim(1).DeviceEnabled = 1.ClearInput() и ClearOutput().DataEventEnabled = 1.Скорректируем функцию подключения торгового оборудования с учетом правильного порядка команд:
Функция ПодключитьСканерШК() Экспорт
Перем barcodeScanner;
Попытка
#Если ВебКлиент Тогда
УстановитьВнешнююКомпоненту("ОбщийМакет.СканерШтрихкода");
ПодключитьВнешнююКомпоненту("ОбщийМакет.СканерШтрихкода", "AddIn.Scanner");
#Иначе
ПодключитьВнешнююКомпоненту("AddIn.Scanner");
#КонецЕсли
barcodeScanner = Новый("AddIn.Scanner");
barcodeScanner.Open("СканерШК");
barcodeScanner.EventName = "BarCodeValue";
// Параметры связи
barcodeScanner.Порт = 3;
barcodeScanner.Скорость = 9600;
barcodeScanner.БитДанных = 8;
barcodeScanner.СтопСимвол = 13; // Код символа возврата каретки (CR)
// Захватываем устройство ПЕРЕД включением
barcodeScanner.Claim(1000);
barcodeScanner.DeviceEnabled = 1;
// Очищаем очереди и разрешаем передачу событий
barcodeScanner.ClearInput();
barcodeScanner.ClearOutput();
barcodeScanner.AutoDisable = 0;
barcodeScanner.DataEventEnabled = 1;
barcodeScanner.FreezeEvents = 0;
Исключение
Сообщить("Ошибка подключения сканера: " + ОписаниеОшибки());
barcodeScanner = Неопределено;
КонецПопытки;
Возврат barcodeScanner;
КонецФункции
Проанализируем аппаратную часть. Для того чтобы компонента понимала, где заканчивается считанная последовательность символов, в ее свойствах задается стоп-символ (чаще всего это код 13, соответствующий клавише Enter или возврату каретки CR). Если сканер штрихкода не настроен на отправку суффикса CR после каждого штрихкода, драйвер будет бесконечно ожидать завершения строки, накапливая данные в буфере и не передавая их в процедуру ВнешнееСобытие.
Для исправления этой проблемы необходимо взять руководство пользователя к сканеру (User Guide) и отсканировать управляющий штрихкод добавления суффикса CR (Carriage Return) или CR/LF.
Рассмотренная компонента ScanOPOS (AddIn.Scanner) является устаревшей 32-битной технологией, которая не поддерживается в 64-битных клиентах и вызывает системные конфликты на современных версиях Windows. В современных конфигурациях рекомендуется использовать драйверы стандарта 1С:Совместимо на базе технологии NativeApi из состава «1С:Библиотеки подключаемого оборудования» (БПО).
Использование нативного драйвера позволяет работать со сканером как через виртуальный COM-порт, так и в режиме клавиатурного перехвата (HID), автоматически решая проблемы блокировки очереди событий и зависания системных портов.