Почему падает 1С при закрытии формы с компонентой vk_rs232 и как это исправить?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции оборудования через последовательный интерфейс (COM-порт / RS-232) разработчики часто сталкиваются с устаревшими внешними библиотеками. Одной из распространенных проблем является ситуация, когда внешняя компонента vk_rs232.dll корректно принимает и отправляет сигналы, однако в момент закрытия экранной формы весь рабочий сеанс программы аварийно закрывается с ошибкой нарушения прав доступа к памяти.

Проанализируем технические причины такого поведения платформы, рассмотрим шаги для устранения сбоя в существующем коде, а также разберем надежные альтернативные способы работы с портом и входящими данными.

Выясним причину аварийного завершения

Сбой при закрытии формы происходит на системном уровне из-за специфики архитектуры старых внешних компонент (созданных по технологии COM AddIn на Delphi или C++):

  1. Конфликт фонового потока опроса и деструктора: библиотека запускает отдельный системный поток для непрерывного чтения входящего буфера порта. При закрытии формы платформа 1С уничтожает контекст формы и связанные переменные. Если фоновый поток библиотеки не успевает мгновенно остановиться, он обращается по указателю к уже несуществующему в памяти интерфейсу обратного вызова 1С (точка входа для генерации внешнего события). Это вызывает ошибку Access Violation (0xC0000005) и мгновенный краш процесса.
  2. Заблокированный дескриптор порта: если программное закрытие порта не выполнено до момента разрушения окна, системный дескриптор Windows API остается занятым, а деструктор библиотеки завершается с ошибкой.

Способ 1. Корректный порядок выгрузки компоненты в событиях формы

Разберем по шагам, как предотвратить падение при использовании исходной библиотеки. Главная задача — принудительно отключить опрос оборудования и освободить память до того, как платформа начнет уничтожать элементы интерфейса.

  1. Перейдем в модуль управляемой или обычной формы, где подключена компонента.
  2. В обработчик события ПередЗакрытием или ПриЗакрытии добавим явный вызов метода остановки порта.
  3. Явно обнулим переменную, содержащую объект компоненты, присвоив ей значение Неопределено.

Посмотрим на пример правильного освобождения ресурсов:


&НаКлиенте
Процедура ПередЗакрытием(Отказ, ЗавершениеРаботы, ТекстПредупреждения, СтандартнаяОбработка)
    Если ОбъектВК <> Неопределено Тогда
        Попытка
            // Принудительно закрываем соединение с портом
            ОбъектВК.ЗакрытьПорт();
        Исключение
            // Игнорируем ошибки при закрытии, если порт уже был недоступен
        КонецПопытки;
        
        // Разрываем ссылку на объект для корректной очистки памяти
        ОбъектВК = Неопределено;
    КонецЕсли;
КонецПроцедуры

Способ 2. Использование альтернативного COM-объекта (MSComm32 / ZComm32)

Если используемая сборка vk_rs232 продолжает аварийно завершать работу даже после явного закрытия, рассмотрим переход на классический компонентный интерфейс Windows, аналогичный mscomm32.ocx или zcomm32.commport. Данные компоненты стабильно управляют дескрипторами операционной системы и позволяют перехватывать входящие байты через события 1С.

Разберем реализацию подключения и чтения через обработчик внешних событий:


&НаКлиенте
Перем ОбъектПорта;

&НаКлиенте
Процедура ИнициализироватьПорт(Команда)
    Если ОбъектПорта = Неопределено Тогда
        Попытка
            ОбъектПорта = Новый COMОбъект("zcomm32.commport");
        Исключение
            Сообщить("Не удалось загрузить COM-объект работы с портом: " + ОписаниеОшибки());
            Возврат;
        КонецПопытки;

        // Подключаем процедуру обработки входящего потока данных
        ДобавитьОбработчик ОбъектПорта.OnComm, ОбработкаВходящихДанных;
        
        // Задаем параметры подключения
        ОбъектПорта.CommPort = 1; // Номер COM-порта
        ОбъектПорта.Settings = "9600,N,8,1"; // Скорость, четность, бит данных, стоп-бит
        ОбъектПорта.InputMode = 1; // 1 — режим массива байтов, 0 — текстовый режим

        Попытка
            ОбъектПорта.PortOpen = Истина;
        Исключение
            ОбъектПорта = Неопределено;
            Сообщить("Ошибка открытия порта: " + ОписаниеОшибки());
        КонецПопытки;
    КонецЕсли;
КонецПроцедуры

&НаКлиенте
Процедура ОбработкаВходящихДанных()
    // Получаем массив байтов из буфера компоненты
    МассивБайтов = ОбъектПорта.Input.Выгрузить();
    
    Если МассивБайтов.Количество() >= 4 Тогда
        Сообщить("Получены первые байты: " + Строка(МассивБайтов[0]) + ", " + Строка(МассивБайтов[1]));
    КонецЕсли;
    
    // При необходимости отправляем подтверждение обратно в порт
    ОбъектПорта.OutPut = "OK";
КонецПроцедуры

Способ 3. Преобразование входящих шестнадцатеричных (HEX) данных в читаемый текст

При использовании модифицированных или альтернативных библиотек данные из буфера нередко возвращаются в виде строки шестнадцатеричных кодов (например, "03415E42") вместо готовой ASCII-строки. Чтобы преобразовать HEX-строку в осмысленный текст или числовое значение, воспользуемся штатным функционалом платформы 1С 8.3 для работы с двоичными данными.

Рассмотрим пример декодирования HEX-последовательности в строку:


&НаКлиенте
Функция ПреобразоватьHEXВТекст(ВходящаяСтрокаHEX)
    // Преобразуем шестнадцатеричное представление в объект ДвоичныеДанные
    ДвоичныеДанные = ПолучитьДвоичныеДанныеИзШестнадцатеричнойСтроки(ВходящаяСтрокаHEX);
    
    // Восстанавливаем строку с указанием требуемой кодировки оборудования (ANSI / Windows-1251)
    Результат = ПолучитьСтрокуИзДвоичныхДанных(ДвоичныеДанные, КодировкаТекста.ANSI);
    
    Возврат Результат;
КонецФункции

Если же необходимо выполнить побайтовый разбор или перевести отдельный байт из шестнадцатеричной системы в десятичное число, разберем вспомогательную функцию преобразования:


&НаКлиенте
Функция Из16В10(Значение16)
    Символы16 = "0123456789ABCDEF";
    СтрокаHEX = ВРег(СокрЛП(Значение16));
    Результат = 0;
    
    Для Индекс = 1 По СтрДлина(СтрокаHEX) Цикл
        Символ = Сред(СтрокаHEX, Индекс, 1);
        Позиция = СтрНайти(Символы16, Символ) - 1;
        Если Позиция < 0 Тогда
            Возврат 0; // Некорректный символ
        КонецЕсли;
        Результат = Результат * 16 + Позиция;
    КонецЦикла;
    
    Возврат Результат;
КонецФункции

Важные ограничения и рекомендации

При работе с внешними библиотеками COM-портов учитывайте ключевые особенности платформы:

  1. Разрядность клиента: библиотеки vk_rs232.dll, mscomm32.ocx и их модификации существуют преимущественно в 32-разрядном (x86) исполнении. При запуске 64-разрядного клиента 1С загрузка таких компонент вызовет ошибку инициализации. Для их работы необходимо устанавливать 32-битный дистрибутив платформы.
  2. Ограничения веб-клиента и Linux: COM-компоненты и ActiveX-элементы функционируют исключительно в операционной системе Windows в толстом или тонком клиенте. Они не поддерживаются в веб-клиенте и на рабочих станциях под управлением Linux.
  3. Использование Библиотеки подключаемого оборудования (БПО): для долгосрочных промышленных решений рекомендуется отказаться от самодельных COM-компонент в пользу штатных сертифицированных драйверов БПО на базе технологии Native API, которые корректно работают в многопоточной среде и изолированы от сбоев интерфейса.
← На главную