Разработка и подключение собственных внешних компонент (ВК) для платформы «1С:Предприятие 8.3» — это отличный способ расширить стандартные возможности системы. Часто ВК пишутся на Delphi для интеграции с торговым или промышленным оборудованием, например, для работы с COM-портами, USB-устройствами, весами или сканерами. Однако при первой же попытке запустить скомпилированную библиотеку на стороне клиента разработчики часто сталкиваются с ошибками инициализации.
В этой статье мы подробно разберем, почему возникает ошибка при вызове методов загрузки внешних компонент, как влияет разрядность операционной системы и платформы 1С на этот процесс, а также рассмотрим переход от устаревшей технологии COM к современному стандарту Native API.
Рассмотрим классический пример, с которого начинают многие разработчики. Допустим, у нас имеется скомпилированная динамическая библиотека testvk.dll, созданная на Delphi. Традиционный (но устаревший) способ работы с ней в коде 1С выглядит следующим образом:
&НаКлиенте
Процедура КомандаПодключитьВК(Команда)
ПутьКФайлу = "C:\1\Шаблон ВК\TestVK\DLL\testvk.dll";
// Попытка зарегистрировать и загрузить библиотеку
Результат = ПодключитьВнешнююКомпоненту(ПутьКФайлу, "AveRomix", ТипВнешнейКомпоненты.COM);
Если Результат Тогда
Попытка
ОбъектВК = Новый ("AddIn.AveRomix.TestVK");
Сообщить("Компонента успешно подключена и объект создан!");
Исключение
Сообщить("Ошибка при создании объекта: " + ОписаниеОшибки());
КонецПопытки;
Иначе
Сообщить("Не удалось подключить внешнюю компоненту.");
КонецЕсли;
КонецПроцедуры
При использовании этого кода функция ПодключитьВнешнююКомпоненту очень часто возвращает Ложь, либо падает с ошибкой на этапе инициализации. Проанализируем ключевые причины такого поведения системы.
Основная проблема, из-за которой внешняя компонента отказывается загружаться, заключается в несовместимости архитектур (разрядностей) исполняемого файла 1С и динамической библиотеки DLL:
1cv8.exe или 1cv8c.exe имеет архитектуру x64), он физически не сможет загрузить в свое адресное пространство 32-разрядную библиотеку testvk.dll.Возможность компиляции под x64 появилась в среде Delphi только начиная с версии XE2. Если у вас нет доступа к современным коммерческим версиям Delphi, отличным бесплатным решением станет переход на кроссплатформенную среду Lazarus (FreePascal). Она полностью совместима с синтаксисом Object Pascal и позволяет компилировать библиотеки под любые операционные системы и архитектуры (включая Windows x64 и Linux x86/x64).
Использование COM-технологии для внешних компонент накладывает серьезные ограничения:
Regsvr32. Для этого пользователю необходимы права администратора, что часто невозможно в корпоративной среде с жесткими политиками безопасности (UAC).Современным стандартом разработки для платформы 1С является технология Native API. Она лишена указанных недостатков:
Для быстрой разработки Native API компонент на Delphi или Lazarus рекомендуется использовать готовую бесплатную библиотеку с открытым исходным кодом 1CNativeLib. Она содержит все необходимые обертки интерфейсов сопряжения с 1С, избавляя вас от написания низкоуровневого кода взаимодействия с виртуальной машиной 1С.
Чтобы избавить себя от необходимости вручную проверять разрядность клиента 1С в коде и загружать разные файлы, мы можем использовать встроенный механизм платформы 1С — механизм манифестов. Для этого выполним следующие шаги:
my_vk_x32.dll и my_vk_x64.dll.MANIFEST.xml следующего содержания:
<?xml version="1.0" encoding="UTF-8"?>
<bundle xmlns="http://v8.1c.ru/8.2/addin/bundle">
<component os="Windows" arch="i386" path="my_vk_x32.dll" shared="true"/>
<component os="Windows" arch="x86_64" path="my_vk_x64.dll" shared="true"/>
</bundle>
MyComponent.zip.Теперь напишем универсальный код для безопасного подключения нашей компоненты на клиенте. Платформа 1С сама проанализирует операционную систему, разрядность запущенного сеанса 1С, распакует из архива нужную версию DLL во временную папку пользователя и подключит её:
&НаКлиенте
Функция ПодключитьНативнуюКомпоненту() Экспорт
ИмяМакета = "Обработка.МояОбработкаОбслуживания.Макет.КомпонентаMyVK";
ИмяПути = "MyNativeVK";
// Пробуем подключить компоненту из кэша платформы
Результат = ПодключитьВнешнююКомпоненту(ИмяМакета, ИмяПути, ТипВнешнейКомпоненты.Native);
Если Не Результат Тогда
// Если не удалось, инициируем установку/обновление компоненты на клиенте
УстановитьВнешнююКомпоненту(ИмяМакета);
// Повторяем попытку подключения
Результат = ПодключитьВнешнююКомпоненту(ИмяМакета, ИмяПути, ТипВнешнейКомпоненты.Native);
КонецЕсли;
Если Результат Тогда
Возврат Новый("AddIn.MyNativeVK.Extension"); // "Extension" - имя объекта, заданное внутри ВК
Иначе
Сообщить("Ошибка: невозможно загрузить внешнюю компоненту MyVK!");
Возврат Неопределено;
КонецЕсли;
КонецФункции
Начиная с версии платформы 8.3.21, разработчикам стал доступен новый параметр безопасности — изолированный режим запуска внешних компонент. По умолчанию на сервере и в некоторых сценариях на клиенте система пытается изолировать выполнение стороннего кода.
При использовании метода ПодключитьВнешнююКомпоненту мы можем явно указать этот параметр:
Результат = ПодключитьВнешнююКомпоненту(ИмяМакета, ИмяПути, ТипВнешнейКомпоненты.Native, ТипПодключенияВнешнейКомпоненты.Изолированно);
Преимущество изолированного режима: Если ваша Delphi-компонента совершит критическую ошибку (например, вызовет Access Violation из-за некорректной работы с памятью или сбоя драйвера COM-порта), процесс самого клиента 1С не завершится аварийно. Упадет только изолированный контейнер компоненты. Это повышает общую отказоустойчивость системы автоматизации.
Если же ваша компонента должна взаимодействовать с графическим интерфейсом операционной системы (например, захватывать фокус окон или выводить собственные формы поверх окон 1С), то изолированный режим может блокировать такие действия. В таком случае используйте параметр ТипПодключенияВнешнейКомпоненты.НеИзолированно.
Поскольку автор исходного вопроса планирует использовать компоненту для управления исполнительным устройством через виртуальный COM-порт (USB-интерфейс), выделим важные архитектурные рекомендации:
ВнешнееСобытие, которая мгновенно и без лишней нагрузки на интерфейс отреагирует на пришедшие от оборудования данные:
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
Если Источник = "MyNativeVK" Тогда
ПроанализироватьДанныеОтПорта(Данные);
КонецЕсли;
КонецПроцедуры
Применение кроссплатформенной среды Lazarus, компиляция библиотек под x32 и x64 архитектуры с использованием манифеста, а также переход на Native API позволят вам создавать быстрые, надежные и безопасные внешние компоненты для любых версий платформы «1С:Предприятие 8.3».