При интеграции 1С:Предприятия с различным торговым и промышленным оборудованием (весы, сканеры, фискальные регистраторы, RFID-считыватели) разработчики часто используют классический элемент управления MSCOMM32.ocx для прямой работы с последовательными COM-портами. Однако при отправке управляющих команд или пакетов данных очень часто возникает неприятная проблема: символы с кодами от 0 до 127 передаются корректно, а все байты со значениями выше 127 (от 128 до 255, то есть диапазон 0x80 – 0xFF) искажаются, превращаясь в знаки вопроса (байт 0x3F) или другие непредвиденные символы.
В рамках этой статьи мы подробно разберем, почему возникает это искажение, проанализируем поведение системы, рассмотрим временные обходные пути и реализуем максимально правильное, производительное и современное решение проблемы штатными средствами платформы 1С.
Для того чтобы понять природу проблемы, проанализируем, как 1С работает со строками и передает их во внешние COM-объекты. Внутреннее представление строковых данных в платформе 1С:Предприятие основано на стандарте Unicode (кодировка UTF-16), где каждый символ занимает 2 байта. В то же время старые COM-объекты, такие как MSCOMM32, изначально проектировались в эпоху доминирования однобайтовых кодировок (ANSI/ASCII).
Когда мы пытаемся передать строку во внешнее свойство КомПорт.Output, операционная система Windows и платформа 1С выполняют неявную конвертацию строки Unicode в однобайтовую кодировку ANSI (формат BSTR). Процесс конвертации происходит следующим образом:
0x3F в шестнадцатеричной системе). Именно это мы и видим на дампе принимающей стороны.Попытка сформировать строку через конструкцию вида Символ(248) + Символ(85)... приводит к тому, что 1С создает строку Юникода с соответствующими кодовыми точками. При передаче этой строки в свойство Output компонента MSCOMM32 происходит трансляция в системную кодировку ANSI, ломая исходную последовательность байтов.
Часто у разработчиков возникает логичная идея: если строка искажается из-за конвертации кодировок, нужно передать данные в виде массива чисел (байтов). Однако простая передача стандартного объекта типа Массив в 1С вызывает ошибку времени выполнения.
Дело в том, что COM-объекты не умеют напрямую работать с внутренними типами данных 1С. Платформа передает стандартный массив как объект типа VT_DISPATCH (ссылка на интерфейс автоматизации). Элемент управления MSCOMM32 ожидает на входе либо строковый буфер, либо специализированный безопасный массив байтов — SAFEARRAY. Получив несовместимый тип данных, компонент аварийно завершает операцию с ошибкой несоответствия типов (Type Mismatch).
Один из обходных путей, к которому часто прибегают разработчики, заключается в делегировании формирования строки интерпретатору VBScript. Поскольку VBScript работает напрямую со структурами ActiveX и корректно формирует строковые типы данных без посредничества механизмов конвертации 1С, этот способ позволяет получить требуемый результат.
Рассмотрим пример функции, реализующей этот подход:
Функция ВернутьСтрVBScript(Стр)
// Инициализируем скриптовый движок
sc = Новый COMОбъект("MSScriptControl.ScriptControl");
sc.language = "VBscript";
Команда = "";
// Преобразуем каждый символ строки через системную функцию Chr на стороне VBScript
Для н = 1 По СтрДлина(Стр) Цикл
Команда = Команда + sc.eval("Chr(""" + КодСимвола(Стр, н) + """)");
КонецЦикла;
Возврат Команда;
КонецФункции
Этот метод действительно работает и позволяет обойти проблему искажения старших байтов. Однако мы настоятельно не рекомендуем использовать его в реальных коммерческих решениях по ряду критических причин:
MSScriptControl.ScriptControl является строго 32-битным компонентом. Если ваша база данных будет запущена под 64-битным клиентом 1С или этот код выполнится на 64-битном сервере приложений, система выдаст неустранимую ошибку «Класс не зарегистрирован».sc.eval() в цикле для каждого байта порождает огромные накладные расходы на инициализацию парсера и выполнение микроскриптов. Это недопустимо при интенсивном обмене данными.MSScriptControl официально признан Microsoft устаревшим и во многих современных сборках Windows 10/11 заблокирован политиками безопасности по умолчанию.Наиболее надежным, быстрым и штатным способом передачи бинарных данных в COM-объекты из платформы 1С является использование специализированного объекта COMSafeArray. Этот объект позволяет создать типизированный массив, который на системном уровне преобразуется в стандартный SAFEARRAY, понятный для любого внешнего COM-компонента.
Для передачи произвольных байтов без искажения нам необходимо инициализировать массив с типом VT_UI1 (Unsigned 1-byte integer — беззнаковое целое число размером 1 байт, соответствующее типу Byte в C++ и VB).
Разберем этот процесс по шагам на практическом примере:
// Шаг 1. Переводим COM-порт в режим работы с бинарными данными
// По умолчанию MSCOMM32 может ожидать текстовый режим (comInputModeText = 0)
// Нам необходимо принудительно установить бинарный режим (comInputModeBinary = 1)
КомПорт.InputMode = 1;
// Шаг 2. Создаем обычный массив 1С и заполняем его необходимыми числовыми кодами байтов
МассивБайтов = Новый Массив;
МассивБайтов.Добавить(248); // f8 в hex-представлении
МассивБайтов.Добавить(85); // 55
МассивБайтов.Добавить(206); // ce
МассивБайтов.Добавить(1); // 01
МассивБайтов.Добавить(0); // 00
МассивБайтов.Добавить(144); // 90
МассивБайтов.Добавить(144); // 90
МассивБайтов.Добавить(0); // 00
// Шаг 3. Оборачиваем подготовленный массив в системный объект COMSafeArray.
// Вторым параметром передаем тип данных "VT_UI1", третьим — размерность массива.
РазмерМассива = МассивБайтов.Количество();
МассивCOM = Новый COMSafeArray(МассивБайтов, "VT_UI1", РазмерМассива);
// Шаг 4. Отправляем полученный массив напрямую в порт
// Данные уйдут в устройство байт-в-байт, минуя трансляции кодировок Windows
КомПорт.Output = МассивCOM;
Этот способ обладает абсолютной надежностью, работает на порядок быстрее любых внешних скриптов, не зависит от разрядности операционной системы (если сам COM-объект поддерживает работу в соответствующей среде) и гарантирует передачу байтов в исходном виде.
Еще один профессиональный способ подготовки «чистых» бинарных данных из строки Юникода заключается в использовании системного объекта ADODB.Stream. Этот подход полезен, когда у вас уже есть готовая текстовая строка (например, сформированная xml-структура или JSON) и вам нужно быстро получить ее бинарный эквивалент в определенной кодовой странице (например, Windows-1251 или UTF-8) для отправки в COM-порт.
Проанализируем пример кода с использованием этого механизма:
Функция ПреобразоватьСтрокуВБинарныйДанные(ИсходнаяСтрока, НужнаяКодировка = "windows-1251")
// Создаем поток ADODB
Поток = Новый COMОбъект("ADODB.Stream");
Поток.Type = 2; // Указываем тип потока: текстовый
Поток.Charset = НужнаяКодировка;
Поток.Open();
// Записываем нашу строку в поток
Поток.WriteText(ИсходнаяСтрока);
// Переводим поток в бинарный режим для чтения сырых байтов
Поток.Position = 0;
Поток.Type = 1; // Переключаем тип на бинарный (Binary)
// Считываем двоичные данные, которые возвращаются в формате SAFEARRAY (VT_UI1)
ДвоичныеДанные = Поток.Read();
Поток.Close();
Возврат ДвоичныеДанные;
КонецФункции
Полученный из функции объект типа VT_UI1 (бинарные данные) можно напрямую присваивать свойству Output вашего COM-порта. Этот метод объединяет удобство работы со строками в 1С и надежность бинарной передачи информации.
В заключение отметим, что использование компонента MSCOMM32.ocx в современных реалиях накладывает жесткие инфраструктурные ограничения. Данный компонент является наследием Visual Basic 6.0, работает исключительно в 32-битных процессах и требует обязательной регистрации в системном реестре Windows с правами администратора (через утилиту regsvr32), что часто вызывает проблемы при развертывании решений на новых рабочих местах.
Если вы проектируете систему «с нуля», рекомендуем рассмотреть более современные альтернативы:
System.IO.Ports.SerialPort из платформы .NET Framework предоставляет мощный, кроссплатформенный и стабильный интерфейс для работы с портами, который легко интегрируется в 1С без регистрации внешних ActiveX-компонент.ДвоичныеДанные и БуферДвоичныхДанных, не зависят от разрядности клиента и могут беспрепятственно работать как на Windows, так и на Linux-системах.