При решении задач высоконагруженных вычислений, интеграции со специфическим торговым или промышленным оборудованием, низкоуровневой работы с сетью или криптографией возможностей встроенного языка 1С может оказаться недостаточно. В таких ситуациях разработчики прибегают к созданию внешних компонент. Разберем основы разработки внешних компонент по современной технологии NativeAPI, ключевые интерфейсы C++, правила управления памятью и порядок внедрения компоненты в конфигурацию «1С:Предприятие 8.3».
Ранее основным механизмом расширения возможностей платформы являлась технология COM (ActiveX). Однако она имела серьезные ограничения: привязка исключительно к операционной системе Windows, необходимость регистрации в системном реестре с правами администратора и сложности при работе на сервере под управлением Linux. Рассмотрим ключевые преимущества NativeAPI:
.dll), Linux (.so), macOS (.dylib), а также на мобильных платформах.regsvr32, она динамически загружается в адресное пространство процесса клиентом или сервером 1С.Рассмотрим, как устроена библиотека изнутри. В официальном комплекте поставки (SDK NativeAPI) предоставляется набор заголовочных файлов C++, определяющих правила взаимодействия между платформой и библиотекой. Разберем основные компоненты взаимодействия:
Библиотека должна экспортировать стандартные точки входа:
GetClassObject — создает экземпляр компоненты и возвращает платформе указатель на интерфейс.
DestroyObject — корректно удаляет созданный объект из памяти.
GetClassNames — возвращает список классов, доступных в данной библиотеке.
SetPlatformCapabilities — согласует функциональные возможности платформы и библиотеки.
IComponentBase:
Это основной интерфейс, который реализует C++ класс внешней компоненты. Через него платформа опрашивает свойства и вызывает методы:
Init и Done — методы инициализации и завершения работы компоненты.
setMemManager — передает в компоненту указатель на менеджер памяти платформы 1С.
GetNProps, FindProp, GetPropVal, SetPropVal — управление свойствами объекта.
GetNMethods, FindMethod, CallAsProc, CallAsFunc — вызов процедур и функций.
RegisterExtensionAs — определяет имя, под которым объект доступен во встроенном языке 1С.
IAddInDefBase:
Интерфейс предоставляется платформой 1С. Он позволяет компоненте отправлять асинхронные события обратно в 1С с помощью метода ExternalEvent. На стороне платформы такие сигналы обрабатываются в процедуре ОбработкаВнешнегоСобытия.
Проанализируем нюансы, которые чаще всего вызывают сбои и аварийное завершение процесса («падение» rphost или 1cv8c.exe):
IMemoryManager):
Все строковые и двоичные данные, которые компонента возвращает в 1С, должны размещаться в памяти, выделенной через интерфейс IMemoryManager->AllocMemory. Если выделить память стандартным оператором new или функцией malloc, платформа 1С при попытке очистить память после вызова метода завершит работу с ошибкой доступа к памяти.
tVariant:
Все параметры методов и значения свойств передаются через структуру tVariant. Она содержит тип данных (число, строка, булево, дата, двоичные данные) и соответствующее значение. При работе со строками платформа использует кодировку UTF-16.
В Windows тип wchar_t занимает 2 байта, тогда как в Linux — 4 байта. В SDK NativeAPI используется тип WCHAR_T (16-битный символ UTF-16), поэтому при кроссплатформенной разработке необходимо выполнять явную конвертацию между внутренними строками C++ (например, std::string UTF-8) и строками WCHAR_T*.
Чтобы внешняя компонента могла бесшовно устанавливаться на клиентских компьютерах и серверах с разными операционными системами, соберем ZIP-архив со структурой поставки. В корень архива поместим скомпилированные файлы и файл описания MANIFEST.XML.
Посмотрим на пример структуры файла MANIFEST.XML:
<bundle name="MyCustomExtension" version="1.0">
<component path="MyComp_win32.dll" type="native" os="Windows" arch="i386"/>
<component path="MyComp_win64.dll" type="native" os="Windows" arch="x86_64"/>
<component path="libMyComp_linux64.so" type="native" os="Linux" arch="x86_64"/>
</bundle>
Сформированный ZIP-архив загружается в конфигурацию в качестве объекта ОбщийМакет с типом Двоичные данные.
Разберем по шагам программный код на стороне 1С для установки, подключения и вызова методов созданной компоненты:
&НаКлиенте
Процедура ПодключитьИВыполнитьКомпоненту()
ИмяМакета = "ОбщийМакет.МояВнешняяКомпонента";
ИмяПодключения = "CustomAddIn";
// Установка компоненты из макета во временный каталог пользователя
РезультатУстановки = УстановитьВнешнююКомпоненту(ИмяМакета);
Если Не РезультатУстановки Тогда
ВызватьИсключение "Не удалось установить внешнюю компоненту!";
КонецЕсли;
// Загрузка библиотеки в процесс
РезультатПодключения = ПодключитьВнешнююКомпоненту(ИмяМакета, ИмяПодключения, ТипВнешнейКомпоненты.Native);
Если Не РезультатПодключения Тогда
ВызватьИсключение "Не удалось подключить внешнюю компоненту NativeAPI!";
КонецЕсли;
// Создание экземпляра объекта компоненты
ОбъектКомпоненты = Новый("AddIn." + ИмяПодключения + ".MyExtensionClass");
// Вызов метода компоненты
ИсходныйТекст = "Тестовые данные для обработки";
РезультатОбработки = ОбъектКомпоненты.ВыполнитьПреобразование(ИсходныйТекст);
Сообщить("Результат из внешней компоненты: " + РезультатОбработки);
КонецПроцедуры
Выясним, как отлаживать C++ код при вызове из 1С:
.pdb для Windows или отладочная информация в .so для Linux).1cv8c.exe или 1cv8.exe, а для серверного вызова — рабочий процесс сервера rphost.exe.