При работе с внешним оборудованием через COM-порты (RS-232) программисты 1С часто сталкиваются с необходимостью использовать библиотеку MSCOMM32.ocx. Если при визуальном проектировании на обычных формах (ActiveX) проблем с назначением событий не возникает, то при динамическом создании объектов в коде процедура связки события с обработчиком становится не столь очевидной. Разберем подробно, как реализовать событийную модель получения данных из порта, чтобы избежать ненадежных методов вроде постоянного опроса буфера по таймеру.
Прежде чем перейти к основному решению, проанализируем ситуацию, когда разработчики пытаются использовать ПодключитьОбработчикОжидания. Подобный подход (polling) имеет ряд критических недостатков:
Событийная модель, предоставляемая библиотекой через onComm, работает оптимально: как только в буфер поступает заданное количество байт, генерируется прерывание, и 1С мгновенно вызывает нужную процедуру.
В платформе 1С:Предприятие 8 существует штатный механизм для связки событий внешних COM-объектов с процедурами модуля. Рассмотрим по шагам, как это реализовать программно.
Сначала создадим сам объект и настроим его параметры. Обратите внимание на свойство RThreshold — именно оно определяет, при каком количестве байт в приемном буфере возникнет событие onComm.
// Создаем объект динамически
ComPort = Новый COMОбъект("MSCOMMLib.MSComm.1");
// Настраиваем параметры подключения
ComPort.CommPort = 9; // Номер порта
ComPort.Settings = "9600,N,8,1"; // Скорость, четность, биты данных, стоп-биты
ComPort.RThreshold = 1; // Событие onComm возникнет при получении хотя бы 1 байта
ComPort.InputLen = 0; // Считывать весь буфер целиком при вызове Input
ComPort.PortOpen = Истина;
// Назначаем обработчик события onComm
// Синтаксис: ДобавитьОбработчик Объект.Событие, НазваниеПроцедуры
ДобавитьОбработчик ComPort.onComm, ОбработкаСобытияOnComm;
Важный нюанс: процедура-обработчик должна находиться в том же модуле, где вызывается ДобавитьОбработчик, и быть доступной для вызова. Если вы работаете в модуле формы, процедура должна быть объявлена без ключевого слова Экспорт (или с ним, если это необходимо по архитектуре).
Теперь рассмотрим, как должна выглядеть сама процедура, принимающая данные от устройства. Проанализируем состояние свойства CommEvent, которое указывает на причину возникновения события.
Процедура ОбработкаСобытияOnComm()
// Проверяем, что событие вызвано именно приходом данных (код 2)
Если ComPort.CommEvent = 2 Тогда
ДанныеИзПорта = ComPort.Input;
// Здесь размещаем логику обработки полученной строки
Сообщить("Получены данные: " + ДанныеИзПорта);
КонецЕсли;
КонецПроцедуры
Важный момент: Свойство InputMode определяет формат данных. Если вы работаете с текстовыми данными, оставьте значение 0 (текст). Если устройство присылает бинарные данные (байты), установите ComPort.InputMode = 1.
При использовании MSCOMM32.ocx и функции ДобавитьОбработчик следует учитывать несколько важных факторов, которые могут повлиять на стабильность системы:
MSCOMM32 является 32-битной. Она будет корректно работать только в 32-битном клиенте 1С. В 64-битном приложении создание этого COM-объекта завершится ошибкой.ДобавитьОбработчик для высокоинтенсивных потоков данных может иногда приводить к аварийному завершению работы платформы 1С. Это связано с тем, что COM-объект генерирует событие в своем потоке, а 1С должна корректно «пробросить» его в контекст выполнения скрипта.HKEY_CLASSES_ROOT\Licenses.Если в процессе эксплуатации вы заметите нестабильность (падения платформы), рассмотрим вариант использования специализированных внешних компонент. Внешняя компонента, написанная по технологии Native API, взаимодействует с 1С через метод ВнешнееСобытие. В этом случае данные попадают в стандартную очередь событий 1С, что является наиболее безопасным и «правильным» способом с точки зрения архитектуры платформы.
Однако, для простых задач или при наличии уже отлаженного кода на MSCOMM32, использование ДобавитьОбработчик является самым быстрым и эффективным способом реализовать полноценный обмен данными с оборудованием без лишних «костылей» в виде таймеров.
Резюмируем: Для программного назначения события используем ДобавитьОбработчик, не забываем устанавливать RThreshold больше нуля и обязательно проверяем код события CommEvent внутри обработчика, так как onComm может срабатывать не только на приход данных, но и на ошибки линии или изменение сигналов квитирования (CTS/DSR).