При разработке и внедрении внешних компонент по технологии Native API программисты часто сталкиваются с ситуацией, когда библиотека идеально работает в контексте клиента, но при переносе вызова на сторону сервера метод ПодключитьВнешнююКомпоненту возвращает Ложь без явного описания ошибки. Разберем по шагам, почему это происходит, как устроен механизм загрузки компонент сервером 1С и как гарантированно устранить неполадку.
Рассмотрим стандартный сценарий: библиотека написана на C++ (например, в среде Visual Studio) с использованием шаблона Native API из документации 1С. В коде конфигурации для подключения компоненты из общего макета используется типовая конструкция:
&НаСервере
Функция ПодключитьСервернуюКомпоненту()
Результат = ПодключитьВнешнююКомпоненту("ОбщийМакет.Компонента", "AddInNativeExtension", ТипВнешнейКомпоненты.Native);
Если Не Результат Тогда
ВызватьИсключение "Не удалось подключить внешнюю компоненту на сервере!";
КонецЕсли;
Возврат Результат;
КонецФункции
Если на клиентском рабочем месте этот код возвращает Истина, а на сервере вызов терпит неудачу, причина практически всегда кроется в одном из четырех факторов: ошибках в ZIP-архиве и файле manifest.xml, несовпадении разрядности процессов, нехватке системных библиотек в операционной системе сервера или ограничениях прав службы 1С.
Выясним главную причину сбоя при загрузке из общего макета — некорректное оформление ZIP-пакета. Платформа 1С строго валидирует состав архива перед извлечением динамических библиотек:
manifest.xml (или MANIFEST.XML) и скомпилированные библиотеки (.dll, .so) должны находиться строго в корне архива. Если при упаковке они оказались внутри вложенной папки, сервер 1С не сможет обнаружить манифест и завершит подключение с результатом Ложь.path в теге <component> должен в точности, с учетом регистра символов, совпадать с именем файла DLL в архиве.os="Windows" и arch="i386", для 64-разрядного сервера — arch="x86_64".Посмотрим на пример корректного файла manifest.xml, поддерживающего обе разрядности Windows-сервера:
<?xml version="1.0" encoding="UTF-8"?>
<bundle xmlns="http://v8.1c.ru/8.2/virtual-resource-system">
<component os="Windows" type="native" path="Component32.dll" arch="i386"/>
<component os="Windows" type="native" path="Component64.dll" arch="x86_64"/>
</bundle>
Проанализируем разрядность серверного процесса 1С. Очень часто на 64-разрядную серверную ОС устанавливается 32-разрядный сервер 1С:Предприятие (или наоборот). Рабочий процесс rphost не сможет загрузить библиотеку, если ее битность отличается от битности самого процесса службы 1С.
rphost.exe — наличие суффикса *32 указывает на 32-битный процесс).rphost.exe скомпилирована 32-битная DLL (архитектура Win32/x86), а для 64-разрядного — 64-битная (архитектура x64).Разберем параметры сборки проекта на C++. Когда внешняя компонента собирается с динамической компоновкой среды выполнения C/C++ (флаг /MD), для ее работы на сервере требуются установленные пакеты Microsoft Visual C++ Redistributable соответствующей версии компилятора.
/MD. Это включит весь необходимый код рантайма внутрь DLL.vcredist_x86.exe или vcredist_x64.exe.GetClassObject, DestroyObject, GetClassNames, SetPlatformCapabilities) объявлены с директивой extern "C" во избежание искажения имен (name mangling).Рассмотрим ограничения со стороны операционной системы и кластера серверов 1С:
USR1CV8. При подключении из макета сервер распаковывает DLL во временный каталог пользователя службы (%TEMP%). Пользователь USR1CV8 должен иметь полные права на запись и исполнение файлов в своем локальном профиле..dll из каталога временных файлов.Для повышения надежности сервера 1С и безопасной отладки Native-компонент на сервере рекомендуется использовать четвертый параметр метода ПодключитьВнешнююКомпоненту — режим изоляции. Это позволяет запускать код C++ в отдельном системном процессе coreconnector, исключая падение рабочего процесса rphost при возможных сбоях в памяти DLL:
&НаСервере
Процедура ПодключитьИзолированно()
Результат = ПодключитьВнешнююКомпоненту(
"ОбщийМакет.Компонента",
"AddInNativeExtension",
ТипВнешнейКомпоненты.Native,
РежимИзоляцииВнешнейКомпоненты.Индивидуальный
);
Если Результат Тогда
ОбъектКомпоненты = Новый("AddIn.AddInNativeExtension.MyExtension");
КонецЕсли;
КонецПроцедуры