При работе с программными продуктами 1С и использованием нескольких сканеров штрих-кода перед разработчиками и пользователями часто встает непростая задача: как заставить эти устройства функционировать параллельно, так чтобы данные от каждого сканера поступали в нужные поля или таблицы формы, не смешиваясь между собой. Особенно остро эта проблема проявляется при использовании сканеров в режиме эмуляции клавиатуры, когда операционная система воспринимает все подключенные сканеры как одно устройство ввода.
Рассмотрим подробнее ситуацию, описанную в теме, и проанализируем возможные пути решения, включая альтернативные подходы и способы диагностики типичных проблем.
Наш пользователь сталкивается с типичной ситуацией: необходимо подключить два сканера штрих-кода к одному компьютеру, работающему с 1С, и направлять данные от каждого из них в разные таблицы одной формы. Первоначальные попытки решить эту задачу включали:
ВнешнееСобытие 1С приходит фрагментированный или смешанный ввод, и корректно разобрать его становится крайне сложно или невозможно. Компьютер воспринимает оба сканера как одну общую клавиатуру, и они фактически «печатают» в один и тот же поток ввода.Таким образом, основная задача — найти способ надежно разделить потоки ввода от нескольких сканеров, особенно при параллельной работе.
Хотя одновременный ввод в режиме эмуляции клавиатуры приводит к смешиванию данных, мы можем попытаться улучшить логику их разбора. Это не гарантирует идеальной работы при настоящем одновременном вводе (система все равно будет обрабатывать их последовательно, но очень быстро), но может помочь в большинстве случаев, когда сканирование происходит с минимальным временным лагом. Этот подход требует глубокой проработки алгоритма в 1С.
Каждому сканеру необходимо настроить уникальный и достаточно длинный префикс, а также уникальный суффикс. Префиксы должны быть такими, чтобы они не могли случайно встретиться в составе обычных штрих-кодов или других префиксов. Например:
_SCA1_, Суффикс _END1__SCA2_, Суффикс _END2_Важно, чтобы суффикс также был уникальным для каждого сканера. Чаще всего сканеры после штрих-кода отправляют символ Enter или Tab. Мы можем перенастроить сканер так, чтобы вместо стандартного символа конца строки он отправлял наш уникальный суффикс.
Основная логика будет располагаться в обработчике события ВнешнееСобытие формы. Когда сканер эмулирует клавиатуру, это событие срабатывает с Источник = "Клавиатура" и Событие = "Нажатие" (или подобным). В параметр Данные прилетает строка, содержащая последовательность символов. Если сканеры работали почти одновременно, эта строка будет представлять собой "кашу" из их выводов.
Наша задача — из этой "каши" выделить полные штрих-коды, обрамленные своими префиксами и суффиксами.
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Источник = "Клавиатура" И Событие = "Нажатие" И Не ПустаяСтрока(Данные) Тогда
// Здесь мы получаем потенциальную "кашу" от всех сканеров
СмешанныеДанные = Данные;
Сообщить("Получены смешанные данные: " + СмешанныеДанные);
// Инициализируем переменные для хранения найденных штрих-кодов
ШтрихКодСканера1 = "";
ШтрихКодСканера2 = "";
// Определяем префиксы и суффиксы, заданные для каждого сканера
Префикс1 = "_SCA1_";
Суффикс1 = "_END1_";
Префикс2 = "_SCA2_";
Суффикс2 = "_END2_";
// Попытка найти и извлечь штрих-коды
// Мы будем искать полные последовательности Префикс-ШтрихКод-Суффикс
// и удалять их из "каши" по мере нахождения, чтобы не обрабатывать повторно
ТекстДляПоиска = СмешанныеДанные;
Пока Истина Цикл
// Ищем штрих-код от Сканера 1
Начало1 = Найти(ТекстДляПоиска, Префикс1);
Если Начало1 > 0 Тогда
Конец1 = Найти(ТекстДляПоиска, Суффикс1, Начало1 + СтрДлина(Префикс1));
Если Конец1 > 0 Тогда
// Найден полный фрагмент от Сканера 1
ШтрихКодСканера1 = Сред(ТекстДляПоиска, Начало1 + СтрДлина(Префикс1), Конец1 - (Начало1 + СтрДлина(Префикс1)));
Сообщить("Найден штрих-код от Сканера 1: " + ШтрихКодСканера1);
ОбработатьШтрихКодОтСканера1(ШтрихКодСканера1);
// Удаляем обработанный фрагмент из текста для дальнейшего поиска
ТекстДляПоиска = СтрЗаменить(ТекстДляПоиска, Префикс1 + ШтрихКодСканера1 + Суффикс1, "");
Продолжить; // Продолжаем поиск в оставшемся тексте
КонецЕсли;
КонецЕсли;
// Ищем штрих-код от Сканера 2
Начало2 = Найти(ТекстДляПоиска, Префикс2);
Если Начало2 > 0 Тогда
Конец2 = Найти(ТекстДляПоиска, Суффикс2, Начало2 + СтрДлина(Префикс2));
Если Конец2 > 0 Тогда
// Найден полный фрагмент от Сканера 2
ШтрихКодСканера2 = Сред(ТекстДляПоиска, Начало2 + СтрДлина(Префикс2), Конец2 - (Начало2 + СтрДлина(Префикс2)));
Сообщить("Найден штрих-код от Сканера 2: " + ШтрихКодСканера2);
ОбработатьШтрихКодОтСканера2(ШтрихКодСканера2);
// Удаляем обработанный фрагмент из текста для дальнейшего поиска
ТекстДляПоиска = СтрЗаменить(ТекстДляПоиска, Префикс2 + ШтрихКодСканера2 + Суффикс2, "");
Продолжить; // Продолжаем поиск в оставшемся тексте
КонецЕсли;
КонецЕсли;
// Если ничего не найдено на этой итерации, выходим из цикла
Прервать;
КонецЦикла;
Если Не ПустаяСтрока(ТекстДляПоиска) Тогда
Сообщить("Не удалось разобрать часть данных: " + ТекстДляПоиска);
КонецЕсли;
КонецЕсли;
КонецПроцедуры
Процедура ОбработатьШтрихКодОтСканера1(ШтрихКод)
// Здесь реализуем логику записи ШтрихКода в Таблицу1 на форме
Сообщить("Сканер 1: Обработан штрих-код '" + ШтрихКод + "' для Таблицы 1.");
// Например: Элементы.Таблица1.ДобавитьСтроку().ШтрихКод = ШтрихКод;
КонецПроцедуры
Процедура ОбработатьШтрихКодОтСканера2(ШтрихКод)
// Здесь реализуем логику записи ШтрихКода в Таблицу2 на форме
Сообщить("Сканер 2: Обработан штрих-код '" + ШтрихКод + "' для Таблицы 2.");
// Например: Элементы.Таблица2.ДобавитьСтроку().ШтрихКод = ШтрихКод;
КонецПроцедуры
Важно: Этот подход требует тщательной отладки. Если сканеры вводят данные очень близко по времени, "каша" может быть сильно перепутана (например, _SCA1_част_SCA2_ь1_END2_ь2_END1_). В таких случаях стандартные строковые функции могут не справиться, и потребуется более сложный алгоритм парсинга, возможно, с использованием регулярных выражений (если они доступны в вашей версии 1С или через внешние компоненты).
Сообщение 2 предлагает вариант, когда мы делаем одно поле на форме, даем ему фокус, и в обработчике ПриИзменении этого поля разбираем данные с префиксами. Этот подход схож с описанным выше, но фокусирует ввод в одно визуальное поле. Это может быть полезно для отладки, но не решает проблему "каши" как таковой. Если сканеры сканируют не одновременно, а по очереди, это поле будет получать данные вида _SCA1_ШК1_END1_, затем _SCA2_ШК2_END2_, и ПриИзменении будет отрабатывать для каждого из них. При одновременном сканировании проблема "каши" останется, и ее все равно придется парсить в ПриИзменении точно так же, как и во ВнешнееСобытие.
Помним, что система в любом случае будет отрабатывать события последовательно. Настоящая одновременность ввода и обработки данных от нескольких устройств в 1С через эмуляцию клавиатуры — это весьма сложная задача, и обычно требует внешних решений.
Проблемы с зависанием COM-портов на терминальном сервере, упомянутые в первом сообщении, являются известными. Однако режим эмуляции COM-порта по своей сути является более надежным способом для разделения нескольких сканеров, поскольку каждое устройство будет иметь свой уникальный порт и, следовательно, свой отдельный поток данных, которые не будут смешиваться. Давайте разберем, как можно попытаться решить эти проблемы:
Убедитесь, что на клиентском компьютере, с которого осуществляется подключение к терминальному серверу, в параметрах подключения к удаленному рабочему столу (MSTSC) установлен флажок перенаправления последовательных портов. Это критично для того, чтобы локальные COM-порты клиента были видны на сервере.
После подключения к терминальному серверу, мы можем проверить, какие COM-порты были перенаправлены. Откройте командную строку на сервере и выполните команду:
change port /query
Эта команда покажет список COM-портов и их текущий статус, а также соответствие локальных портов клиентского компьютера виртуальным портам на сервере (например, COM1 -> TS001\COM1).
Если сканер работает в режиме эмуляции COM-порта, на клиентском компьютере должны быть установлены соответствующие драйверы виртуального COM-порта от производителя сканера. Эти драйверы преобразуют USB-соединение в эмулируемый COM-порт. На сервере терминалов может потребоваться установка OPOS- или JPOS-драйверов, которые являются стандартными интерфейсами для торгового оборудования и могут работать с перенаправленными COM-портами.
Некоторые производители сканеров предлагают специальные драйверы USB-COM, которые специально разработаны для стабильной работы в сложных сетевых окружениях, включая терминальные серверы. Изучите документацию вашего сканера и посетите сайт производителя, чтобы найти наиболее подходящие драйверы.
Убедитесь, что USB-кабели и сами USB-порты на клиентском компьютере работают стабильно. Плохие контакты или некачественные кабели могут приводить к потере связи и "зависаниям".
Если удастся заставить сканеры стабильно работать в режиме эмуляции COM-порта, то каждый сканер будет доступен в 1С как отдельное устройство. В этом случае для работы со сканерами можно использовать стандартные механизмы работы с торговым оборудованием в 1С (например, Объект.ПодключитьОборудование из БСП) или напрямую взаимодействовать с COM-портом, если это требуется. Это значительно упрощает разделение данных, так как мы будем получать события от конкретного COM-порта. При необходимости можно воспользоваться компонентой для надежного разделения потоков данных от нескольких сканеров.
Если вышеуказанные методы не дают желаемого результата, или требуется максимально надежное решение для обработки truly параллельного ввода, стоит рассмотреть более продвинутые подходы, которые часто требуют разработки дополнительных компонентов или использования специализированного ПО.
Один из самых гибких, но требующих программирования вне 1С, подходов — это использование Windows Raw Input API. Этот API позволяет приложениям получать низкоуровневый доступ к "сырым" данным, поступающим от различных устройств ввода (включая сканеры штрих-кода, работающие в режиме эмуляции клавиатуры). Ключевое преимущество Raw Input API заключается в том, что он предоставляет информацию о конкретном устройстве-источнике ввода, даже если операционная система воспринимает его как обычную клавиатуру.
Таким образом, мы можем программно отличить данные, пришедшие от каждого конкретного сканера (например, по Vendor ID и Product ID USB-устройства). Это позволяет решить проблему "каши" при одновременном сканировании. Мы можем:
Источником для каждого сканера.Этот подход требует значительных усилий по разработке, но он обеспечивает наиболее надежное разделение потоков ввода при использовании сканеров в режиме эмуляции клавиатуры.
Для сложных сценариев, особенно в торговле, существуют коммерческие драйверы торгового оборудования, которые предлагают более продвинутые механизмы взаимодействия с несколькими сканерами. Например, такие решения, как Frontol Driver Unit от АТОЛ (хотя это комплексное ПО для касс, его драйверы могут иметь расширенный функционал), или специализированные компоненты для 1С от других разработчиков. Эти драйверы могут иметь внутренние механизмы для лучшей обработки одновременного ввода, предлагать более гибкие настройки префиксов/суффиксов и собственные алгоритмы разбора "каши", если сканеры работают в клавиатурном режиме.
Хотя стандартный компонент "1С:Сканер штрихкода" может поддерживать работу с несколькими устройствами, он зачастую обрабатывает их последовательно и может не решать проблему истинной одновременности в режиме эмуляции клавиатуры без дополнительных настроек или хаков. Для этой задачи можно использовать внешнюю компоненту для программного управления буфером ввода сканеров.
Хотя это не прямое решение для USB-сканеров на ПК, для общего понимания и возможного вдохновения на разработку собственных решений, мы можем рассмотреть существующие программные SDK (например, Scandit MatrixScan, Barkoder Batch MultiScan, Anyline, Scanbot SDK), которые используются, как правило, с камерами мобильных устройств. Эти SDK способны одновременно сканировать несколько штрих-кодов в одном "кадре" или за один проход, автоматически разделяя и интерпретируя их. Это демонстрирует, что технически возможно обрабатывать множество штрих-кодов, поступающих одновременно, и затем разделять их. Такой принцип может быть реализован в пользовательских решениях для 1С, анализирующих и дешифрующих "кашу" от нескольких клавиатурных сканеров, если будет разработана соответствующая внешняя утилита.
Проблема одновременной работы нескольких сканеров штрих-кода, особенно в режиме эмуляции клавиатуры, является одной из самых сложных в автоматизации. Мы выяснили, что стандартные средства Windows и 1С в режиме эмуляции клавиатуры не позволяют надежно разделить потоки ввода от нескольких устройств при их одновременном использовании, что приводит к "каше".
Для решения этой задачи мы рекомендуем следующий порядок действий:
Каждая из этих опций имеет свои компромиссы по стоимости, сложности реализации и надежности. Выбирайте подход, который наилучшим образом соответствует вашим требованиям и возможностям.