При интеграции торгового или производственного оборудования (весов, сканеров, датчиков) через последовательный порт разработчики нередко используют стандартную библиотеку Microsoft MSComm32.ocx. Однако при вызове конструктора Новый COMОбъект("MSCOMMLib.MSComm") на стороне тонкого клиента платформа может выдать исключение: -2147221230(0x80040112): Класс не лицензирован для использования. Разберем, почему возникает эта ошибка, как правильно зарегистрировать библиотеку и какие нюансы следует учесть при работе с COM-портом из 1С.
Элемент управления MSComm32.ocx изначально разрабатывался для среды Visual Basic 6.0 и содержит механизм защиты времени разработки (Design-Time License). В отличие от размещения элемента на экранной форме в среде разработки, динамическое создание объекта через конструктор COM требует обязательного наличия специального ключа в системном реестре Windows.
Когда 1С выполняет инициализацию объекта, операционная система проверяет ветку реестра HKEY_CLASSES_ROOT\Licenses. Если нужной записи нет либо у текущего пользователя операционной системы отсутствуют права на чтение данной ветки, вызов завершается кодом ошибки CLASS_E_NOTLICENSED (0x80040112).
Чаще всего с этой проблемой сталкиваются в следующих сценариях:
.reg) под своей учетной записью локального администратора, а пользователь 1С работает под ограниченной локальной или доменной учетной записью, для которой ключ недоступен.HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Classes\Licenses.MSComm32.ocx существует только в 32-битном исполнении. Если запущен 64-разрядный тонкий клиент 1С (1cv8c.exe x64), создание COM-объекта завершится неудачей.Выясним, как устранить ошибку на клиентском рабочем месте:
ИмяКомпьютера() и ИмяПользователяОС().HKEY_LOCAL_MACHINE (включая узел WOW6432Node для x64 систем), либо регистрационный .reg-файл запускается непосредственно из-под сеанса того пользователя, который работает в 1С.&НаКлиенте, регистрировать компоненту на сервере «1С:Предприятия» не требуется. Регистрация через regsvr32 и внесение лицензии нужны только на клиентской машине, к которой физически подключены весы.Посмотрим на типовой пример опроса весов, в котором создается COM-объект и считываются данные:
&НаКлиенте
Процедура Брутто(Команда)
Попытка
Весы = Новый COMОбъект("MSCOMMLib.MSComm");
Исключение
Сообщить("Ошибка создания объекта MSCommLib: " + ОписаниеОшибки(), СтатусСообщения.Внимание);
Возврат;
КонецПопытки;
Весы.CommPort = 7;
Весы.Settings = "9600,N,8,1";
Весы.InputLen = 0;
Попытка
Весы.PortOpen = 1;
Исключение
Сообщить("Порт занят другим устройством или недоступен.");
Возврат;
КонецПопытки;
тЗапросНаВзвешивание = Символ(2) + "AB03" + Символ(3);
Для Н = 1 По 5 Цикл
Весы.Output = тЗапросНаВзвешивание;
// Потенциально опасный участок: бесконечное ожидание
Пока Весы.InBufferCount < 12 Цикл
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
КонецЦикла;
См = Весы.Input;
// Дальнейший парсинг строки...
КонецЦикла;
Весы.PortOpen = 0;
КонецПроцедуры
Проанализируем скрытые уязвимости, присутствующие в приведенном фрагменте:
Пока Весы.InBufferCount < 12 Цикл ожидает поступления строго 12 байт. Если весы отключены, выключено питание или произошел сбой интерфейса, программа намертво зависнет с загрузкой процессорного ядра на 100%. Метод ОбработкаПрерыванияПользователя() не защищает от зависания интерфейса при отсутствии реакции оператора. Обязательно должен быть реализован счетчик таймаута.Весы.PortOpen = 0 расположено в самом конце процедуры. Если при разборе строки (например, при вызове функции Число()) возникнет ошибка, выполнение прервется, а порт останется монопольно захваченным процессом 1С. Все последующие попытки взвешивания будут завершаться ошибкой.Перепишем алгоритм так, чтобы гарантировать освобождение порта и предотвратить зависание программы:
&НаКлиенте
Процедура ПолучитьВесБезопасно(Команда)
Попытка
Весы = Новый COMОбъект("MSCOMMLib.MSComm");
Исключение
Сообщить("Не удалось инициализировать MSComm: " + ОписаниеОшибки());
Возврат;
КонецПопытки;
Весы.CommPort = 7;
Весы.Settings = "9600,N,8,1";
Весы.InputLen = 0;
Попытка
Весы.PortOpen = 1;
Исключение
Сообщить("Не удалось открыть COM-порт. Проверьте подключение устройства.");
Возврат;
КонецПопытки;
ЗнСВесов = 0;
тЗапрос = Символ(2) + "AB03" + Символ(3);
Попытка
Для ПопыткаОпроса = 1 По 5 Цикл
Весы.Output = тЗапрос;
// Защита от зависания: ограничиваем максимальное число итераций ожидания
ИтерацийОжидания = 0;
Пока Весы.InBufferCount < 12 И ИтерацийОжидания < 50000 Цикл
ИтерацийОжидания = ИтерацийОжидания + 1;
#Если Клиент Тогда
ОбработкаПрерыванияПользователя();
#КонецЕсли
КонецЦикла;
Если Весы.InBufferCount >= 12 Тогда
Ответ = Весы.Input;
Ответ = СтрЗаменить(Ответ, Символ(3), "");
Ответ = Сред(СтрЗаменить(Ответ, Лев(тЗапрос, 3), ""), 2);
Ответ = Лев(Ответ, СтрДлина(Ответ) - 2);
ЗнСВесов = Число(Ответ);
Прервать;
КонецЕсли;
КонецЦикла;
Исключение
Сообщить("Ошибка при чтении данных с весов: " + ОписаниеОшибки());
КонецПопытки;
// Гарантированное закрытие порта
Если Весы.PortOpen = 1 Тогда
Весы.PortOpen = 0;
КонецЕсли;
Если ЗнСВесов > 0 Тогда
Объект.Брутто = ЗнСВесов;
Объект.РучнойВводБрутто = Ложь;
Объект.ДатаПолученияБрутто = ТекущаяДата();
КонецЕсли;
КонецПроцедуры
Использование устаревших COM-компонент времен Visual Basic 6.0 влечет за собой сложности с лицензированием, несовместимость с 64-битными клиентами и невозможность работы на ОС Linux. Рекомендуется рассмотреть более надежные решения: