В процессе разработки или кастомизации конфигураций 1С часто возникает необходимость подключить торговое оборудование, в частности сканер штрихкодов, напрямую, минуя тяжеловесную Библиотеку подключаемого оборудования (БПО). Это позволяет сохранить проект легковесным, избежать переноса десятков справочников, общих модулей и регистров, а также упростить обновление системы.
В этой статье мы подробно разберем, как реализовать подключение сканера штрихкодов в режиме эмуляции COM-порта (или клавиатуры) на управляемых формах платформы 1С:Предприятие 8.3, используя современную технологию Native API и асинхронные вызовы.
При переходе со старых обычных форм на управляемые интерфейсы многие разработчики пытаются использовать привычные методы работы с внешними компонентами. Типичный legacy-подход выглядит следующим образом: регистрируется библиотека ScanOPOS.dll или драйвер АТОЛ в операционной системе через утилиту regsvr32, после чего в коде вызывается метод ЗагрузитьВнешнююКомпоненту() с жестко прописанным локальным путем (например, e:\Scanner.dll) и создается COM-объект Новый COMОбъект("AddIn.Scaner").
Такой подход порождает целый ряд критических проблем:
regsvr32 требует повышенных привилегий, что крайне неудобно в корпоративной среде или при работе в терминальном режиме.Рассмотрим, как решить эти проблемы с использованием современных и безопасных стандартов разработки на платформе 1С:Предприятие 8.3.
Для реализации кроссплатформенного и отказоустойчивого решения мы откажемся от устаревшей технологии COM в пользу Native API. Современный драйвер от 1С называется «1С:Сканеры штрихкода (NativeApi)». Он поставляется в виде многоплатформенного архива, который содержит бинарные файлы под любые операционные системы (Windows, Linux, macOS) и разрядности (x86/x64).
Вместо обращения к реестру Windows мы будем использовать программный идентификатор (ProgID) Native-компоненты: AddIn.Scanner.InputDevice.
Разберем по шагам весь процесс: от хранения библиотеки в конфигурации до перехвата отсканированных данных.
Чтобы избежать привязки к локальным путям на диске пользователя, мы поместим архив с драйвером непосредственно в конфигурацию 1С. Для этого выполним следующие действия:
1CBarcodeScanner.zip (его можно выгрузить из любого актуального релиза БПО или скачать с сайта поддержки пользователей 1С).Драйвер1ССканерШтрихкода, и выберем тип макета Двоичные данные.Теперь драйвер будет автоматически доставляться на компьютер любого пользователя при первом же обращении к функционалу сканирования.
Начиная с версии платформы 8.3.15, использование синхронных методов работы с файлами и компонентами крайне не рекомендуется, а в Web-клиенте — полностью заблокировано. Нам необходимо применить асинхронную модель инициализации с использованием объекта ОписаниеОповещения.
Напишем процедуру, которая запускает процесс фонового подключения компоненты из нашего общего макета:
&НаКлиенте
Процедура ПодключитьСканерАсинхронно()
// Создаем описание оповещения, указывая процедуру обратного вызова
Оповещение = Новый ОписаниеОповещения("ПослеПодключенияКомпоненты", ЭтотОбъект);
// Используем асинхронный метод платформы
НачатьПодключениеВнешнейКомпоненты(
Оповещение,
"ОбщийМакет.Драйвер1ССканерШтрихкода",
"Scanner",
ТипВнешнейКомпоненты.Native
);
КонецПроцедуры
После того как внешняя компонента успешно загружена в сеанс клиента, управление передается в процедуру обратного вызова. Здесь нам необходимо создать экземпляр объекта драйвера и задать параметры его работы.
Обратите внимание, что в Native API свойства настраиваются не напрямую (как это было в старых COM-объектах), а через универсальный метод УстановитьПараметр(). Рассмотрим пример реализации:
&НаКлиенте
Перем ОбъектДрайвера; // Переменная для хранения активного объекта драйвера на клиенте
&НаКлиенте
Процедура ПослеПодключенияКомпоненты(Результат, Параметры) Экспорт
Если Результат Тогда
Попытка
// Создаем экземпляр устройства
ОбъектДрайвера = Новый("AddIn.Scanner.InputDevice");
// Задаем параметры подключения
// Port = 0 означает режим клавиатуры (Keyboard emulation),
// Значения > 0 соответствуют номерам COM-портов (например, 1 для COM1, 3 для COM3)
ОбъектДрайвера.УстановитьПараметр("Port", 0);
// Настройка суффикса. Обычно сканеры посылают символ перевода строки (Enter), код ASCII - 13
ОбъектДрайвера.УстановитьПараметр("Suffix", 13);
// Если используется COM-порт, можно задать скорость и другие параметры:
// ОбъектДрайвера.УстановитьПараметр("Speed", 9600);
// ОбъектДрайвера.УстановитьПараметр("DataBits", 8);
// Занимаем устройство на стороне ОС
РезультатПодключения = ОбъектДрайвера.Подключить("СканерШтрихкода");
Если РезультатПодключения Тогда
// Активируем получение событий от устройства
ОбъектДрайвера.УстановитьПараметр("Enabled", Истина);
Сообщить("Сканер успешно подключен и готов к работе!");
Иначе
Сообщить("Не удалось занять устройство. Возможно, порт занят другой программой.");
КонецЕсли;
Исключение
Сообщить("Ошибка при инициализации объекта драйвера: " + ОписаниеОшибки());
КонецПопытки;
Иначе
Сообщить("Не удалось загрузить внешнюю компоненту сканера штрихкодов!");
КонецЕсли;
КонецПроцедуры
Когда сканер считывает штрихкод, внешняя компонента генерирует в платформе 1С специальное внешнее событие. Чтобы форма могла перехватить и обработать эти данные, нам нужно выполнить два действия:
ВнешнееСобытие). Без этой интерактивной привязки процедура в коде просто не сработает!
Источник (имя устройства), Событие (тип события) и Данные (непосредственно штрихкод).
Реализуем обработчик события на клиенте:
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Проверяем, что событие пришло именно от нашего сканера
Если Источник = "СканерШтрихкода" ИЛИ Событие = "BarCodeValue" Тогда
// Очищаем полученную строку от возможных лишних пробелов или управляющих символов
Штрихкод = СокрЛП(Данные);
// Выводим информацию пользователю или запускаем логику поиска товара
ПоказатьОповещениеПользователя("Сканирование", , "Считан штрихкод: " + Штрихкод, БиблиотекаКартинок.Информация);
// Здесь мы можем вызвать серверную процедуру для поиска номенклатуры по штрихкоду
ОбработатьПолученныйШтрихкодНаСервере(Штрихкод);
КонецЕсли;
КонецПроцедуры
Объединим все рассмотренные шаги в единый монолитный шаблон модуля управляемой формы, который вы можете перенести в свою конфигурацию для тестирования:
&НаКлиенте
Перем ОбъектДрайвера;
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Инициируем подключение оборудования при открытии формы
ПодключитьСканерАсинхронно();
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
// Освобождаем порт устройства при закрытии формы, чтобы не блокировать его для других приложений
Если ОбъектДрайвера <> Неопределено Тогда
Попытка
ОбъектДрайвера.УстановитьПараметр("Enabled", Ложь);
ОбъектДрайвера.Отключить("СканерШтрихкода");
Исключение
// Подавляем ошибки при закрытии
КонецПопытки;
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПодключитьСканерАсинхронно()
Оповещение = Новый ОписаниеОповещения("ПослеПодключенияКомпоненты", ЭтотОбъект);
НачатьПодключениеВнешнейКомпоненты(Оповещение, "ОбщийМакет.Драйвер1ССканерШтрихкода", "Scanner", ТипВнешнейКомпоненты.Native);
КонецПроцедуры
&НаКлиенте
Процедура ПослеПодключенияКомпоненты(Результат, Параметры) Экспорт
Если Результат Тогда
Попытка
ОбъектДрайвера = Новый("AddIn.Scanner.InputDevice");
ОбъектДрайвера.УстановитьПараметр("Port", 0); // 0 - клавиатура, >0 - номер COM-порта
ОбъектДрайвера.УстановитьПараметр("Suffix", 13); // Суффикс Enter
РезультатПодключения = ОбъектДрайвера.Подключить("СканерШтрихкода");
Если РезультатПодключения Тогда
ОбъектДрайвера.УстановитьПараметр("Enabled", Истина);
Иначе
ОбщаяКартинаОшибки = "Не удалось занять устройство!";
ПоказатьПредупреждение(, ОбщаяКартинаОшибки);
КонецЕсли;
Исключение
Сообщить("Ошибка инициализации устройства: " + ОписаниеОшибки());
КонецПопытки;
Иначе
Сообщить("Ошибка загрузки внешней компоненты драйвера!");
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// ВАЖНО: Убедитесь, что эта процедура выбрана в свойствах формы в строке "Внешнее событие"!
Если Событие = "BarCodeValue" Тогда
ОбработатьШтрихкод(Данные);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ОбработатьШтрихкод(Знач Штрихкод)
Штрихкод = СокрЛП(Штрихкод);
// Реализуйте вашу прикладную логику (например, добавление строки в табличную часть)
Сообщить("Успешно считан штрихкод: " + Штрихкод);
КонецПроцедуры
При самостоятельной реализации обмена со сканером вы можете столкнуться с рядом трудностей. Проанализируем наиболее частые из них:
Выясним причину: платформа не может найти указанный макет или имя компоненты внутри архива не соответствует ожиданиям. Проверьте правильность написания пути к общему макету. Также убедитесь, что загруженный zip-архив содержит внутри файл манифеста manifest.xml и соответствующие dll/so файлы драйвера.
Разберем по шагам диагностику этой проблемы:
ВнешнееСобытие в палитре свойств управляемой формы.ВнешнееСобытие генерироваться не будет (символы будут печататься в то поле ввода, где сейчас стоит курсор).Port = 0. Для перехвата клавиатурного ввода в данном случае драйвер должен уметь перехватывать глобальный фокус ввода. Рекомендуется использовать именно режим эмуляции COM-порта, так как он работает стабильно вне зависимости от того, куда наведен курсор мыши.Эта ситуация возникает, если порт сканера уже занят другой запущенной программой (например, другой копией 1С, утилитой настройки сканера или тестовой утилитой драйвера АТОЛ). Обязательно освобождайте устройство при закрытии формы (событие ПриЗакрытии), вызывая методы отключения драйвера. Для решения проблемы одновременной работы нескольких сеансов с одним COM-портом можно использовать утилиту для одновременной работы сканера с несколькими экземплярами 1С.
Использование технологии Native API совместно с асинхронными методами платформы 1С:Предприятие 8.3 позволяет создать быстрое, надежное и кроссплатформенное решение для работы со сканером штрихкодов без привлечения тяжелых библиотек и сложных процедур развертывания ПО на рабочих местах пользователей.