Внешняя библиотека в коде 1С 8.3: три рабочих способа и подводные камни

· 10 мин

Содержание

Произвольную функцию из DLL встроенный язык 1С напрямую не вызывает: аналога Declare из VBA в нём нет. Использовать DLL в 1С можно тремя путями — оформить её как внешнюю компоненту по технологии Native API и подключить через ПодключитьВнешнююКомпоненту(), зарегистрировать как COM-сервер и создать через Новый COMОбъект("ProgID"), либо вызвать через промежуточную программу.

Какой путь выбрать, зависит от того, кто писал библиотеку и где она будет работать: на клиенте, на сервере, под Windows или Linux. Если исходники есть — почти всегда выгоднее Native API: компонента лежит в макете конфигурации и не требует регистрации в реестре.

Что такое DLL с точки зрения 1С и когда она нужна

DLL — динамическая библиотека Windows с готовым кодом. Для платформы 1С важна не сама DLL, а интерфейс, через который с ней можно разговаривать. Платформа понимает два таких интерфейса:

  • 🧩 Native API — собственный протокол 1С для внешних компонент. Библиотека экспортирует строго определённые функции, платформа видит её объекты как AddIn.Имя.Объект.
  • 🔌 COM — стандартная технология Windows. Библиотека регистрируется в реестре, а 1С создаёт её объект по ProgID.

Обычная DLL с функциями вроде int Sum(int a, int b) не подходит ни под один из них. Её придётся обернуть: написать тонкую компоненту Native API или COM-класс, который внутри вызывает нужную функцию.

Типичные задачи, ради которых это делают:

  • 🖨️ работа с оборудованием: сканеры штрихкодов, весы, фискальные регистраторы, считыватели карт;
  • 🔐 криптография и подпись по протоколам, которых нет в платформе;
  • ⚙️ тяжёлые вычисления, которые на встроенном языке идут слишком медленно;
  • 🏦 SDK банков, служб доставки, систем контроля доступа, поставляемые как DLL;
  • 🪟 вызов функций Windows API: работа с окнами, принтерами, оборудованием.

Способы подключения DLL в 1С: сравнение

СпособКогда подходитГде работаетРиски
Внешняя компонента Native APIПишете библиотеку сами или есть исходникиWindows и Linux, клиент и сервер, веб-клиент с расширением браузераНужно знать C++ и SDK 1С; ошибка в компоненте роняет процесс
COM-объектГотовая COM-библиотека или .NET-сборкаТолько WindowsРегистрация на каждом компьютере, проблемы разрядности
Внешняя программаDLL чужая и без исходников, вызовы редкиеТам, где можно запустить exeМедленно: запуск процесса на каждый вызов

Способ 1. Внешняя компонента Native API

Это основной способ для новых разработок. Компоненту упаковывают в ZIP-архив: внутри DLL для Windows разной разрядности, при необходимости .so для Linux, и файл MANIFEST.XML с описанием, какой файл под какую платформу.

Архив кладут в общий макет конфигурации с типом «Внешняя компонента» (или «Двоичные данные»). Дальше компонента подключается по имени макета.

Пример на сервере, где установка компоненты не требуется:

&НаСервереБезКонтекста
Функция СложитьЧерезКомпоненту(А, Б)

    Подключена = ПодключитьВнешнююКомпоненту("ОбщийМакет.МояКомпонента", "Моя",
        ТипВнешнейКомпоненты.Native);
    Если Не Подключена Тогда
        ВызватьИсключение "Не удалось подключить внешнюю компоненту МояКомпонента";
    КонецЕсли;

    Калькулятор = Новый("AddIn.Моя.Калькулятор");
    Возврат Калькулятор.Сложить(А, Б);

КонецФункции

Строка AddIn.Моя.Калькулятор собирается из имени, переданного вторым параметром (Моя), и имени класса, которое компонента сообщает платформе (Калькулятор). Ошибка в любой части даёт исключение при Новый.

На клиенте компоненту сначала устанавливают на компьютер пользователя, затем подключают. В конфигурациях с запретом синхронных вызовов используйте асинхронные методы. Вариант с Асинх/Ждать работает на платформе 8.3.18 и выше:

&НаКлиенте
Перем Компонента;

&НаКлиенте
Асинх Процедура ПодключитьКомпонентуНаКлиенте()

    Если Компонента <> Неопределено Тогда
        Возврат;
    КонецЕсли;

    Местоположение = "ОбщийМакет.МояКомпонента";
    Подключена = Ждать ПодключитьВнешнююКомпонентуАсинх(Местоположение, "Моя",
        ТипВнешнейКомпоненты.Native);

    Если Не Подключена Тогда
        Ждать УстановитьВнешнююКомпонентуАсинх(Местоположение);
        Подключена = Ждать ПодключитьВнешнююКомпонентуАсинх(Местоположение, "Моя",
            ТипВнешнейКомпоненты.Native);
    КонецЕсли;

    Если Подключена Тогда
        Компонента = Новый("AddIn.Моя.Калькулятор");
    Иначе
        Сообщить("Компонента не подключена: проверьте разрядность клиента и состав архива");
    КонецЕсли;

КонецПроцедуры

Если подключение не удаётся только у части пользователей, первым делом сравните разрядность их клиента 1С с составом архива. 64-битный клиент не загрузит 32-битную DLL.

Способ 2. DLL как COM-объект

Подходит для готовых COM-библиотек и сборок .NET. Библиотеку регистрируют в Windows из командной строки, запущенной от имени администратора.

Для обычной COM-DLL:

rem 64-битная библиотека
C:\Windows\System32\regsvr32.exe "C:\Libs\MyLib.dll"

rem 32-битная библиотека на 64-битной Windows
C:\Windows\SysWOW64\regsvr32.exe "C:\Libs\MyLib.dll"

Для сборки .NET Framework используется RegAsm нужной разрядности:

%WINDIR%\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe "C:\Libs\MyNetLib.dll" /codebase /tlb

В самой сборке класс должен быть видим для COM: атрибуты [ComVisible(true)], [Guid("…")] и [ProgId("MyNetLib.Calculator")], открытый конструктор без параметров.

Вызов из 1С:

Попытка
    Калькулятор = Новый COMОбъект("MyNetLib.Calculator");
    Результат = Калькулятор.Sum(2, 3);
Исключение
    ВызватьИсключение "COM-объект не создан: " + ОписаниеОшибки();
КонецПопытки;

Регистрировать библиотеку нужно на каждом компьютере, где выполняется код: на клиентских машинах для &НаКлиенте и на всех рабочих серверах кластера для &НаСервере.

Способ 3. Через промежуточную программу

Если DLL сторонняя, исходников нет и это не COM-сервер, напишите маленькую консольную программу, которая вызывает функцию и печатает результат в файл или stdout. Из 1С её запускают через ЗапуститьПриложение() с ожиданием завершения и читают результат.

Ещё один вариант — сторонние COM-обёртки для вызова произвольных функций Windows API. Они работают, но это чужой код без поддержки: проверьте лицензию и разрядность до использования в рабочей базе.

Передача параметров: соответствие типов 1С и DLL

Больше всего ошибок возникает на стыке типов. Встроенный язык знает свои типы, библиотека — свои, а платформа переводит одно в другое по фиксированным правилам.

Типы в Native API

Параметры приходят в компоненту массивом структур tVariant. Тип каждого значения нужно проверять перед чтением.

Тип 1СТип в компонентеЧто учесть
ЧислоVTYPE_I4 или VTYPE_R8Целое может прийти как I4, дробное — как R8. Обрабатывайте оба
СтрокаVTYPE_PWSTRДвухбайтные символы WCHAR_T, длина в поле wstrLen
БулевоVTYPE_BOOL—
ДатаVTYPE_TMСтруктура tm, без часового пояса
ДвоичныеДанныеVTYPE_BLOBУдобно для передачи файлов и больших массивов
НеопределеноVTYPE_EMPTYПропущенный необязательный параметр

Фрагмент метода компоненты на C++, который складывает два числа:

bool CAddInNative::CallAsFunc(const long lMethodNum, tVariant* pvarRetValue,
                              tVariant* paParams, const long lSizeArray)
{
    if (lMethodNum == eMethSum && lSizeArray == 2)
    {
        if (TV_VT(&paParams[0]) != VTYPE_I4 || TV_VT(&paParams[1]) != VTYPE_I4)
            return false;               // платформа выдаст ошибку вызова метода

        TV_VT(pvarRetValue) = VTYPE_I4;
        TV_I4(pvarRetValue) = TV_I4(&paParams[0]) + TV_I4(&paParams[1]);
        return true;
    }
    return false;
}

Возвращаемую строку или двоичные данные выделяйте только через менеджер памяти платформы — метод AllocMemory интерфейса IMemoryManager. Память, выделенная через new или malloc, приведёт к падению при освобождении.

Типы в COM

Через COM платформа передаёт Число как целое или double, Строку как BSTR, Булево как bool, Дату как DATE. Для массивов есть специальный тип COMSafeArray: обычный Массив 1С не передаётся в метод, ожидающий SAFEARRAY.

Данные = Новый COMSafeArray("VT_I4", 3);
Данные.SetValue(0, 10);
Данные.SetValue(1, 20);
Данные.SetValue(2, 30);
Сумма = Калькулятор.SumArray(Данные);

💡 Структуры, указатели и колбэки через COM из 1С не передать. Если функция DLL ждёт struct*, разложите структуру на простые параметры в своей обёртке.

Обработка ошибок и отладка библиотеки

Ошибки на стороне 1С

  • ❌ ПодключитьВнешнююКомпоненту() вернула Ложь — неверное имя макета, повреждённый архив, нет DLL под нужную разрядность или платформу в MANIFEST.XML.
  • ❌ Исключение на Новый("AddIn…") — опечатка в имени объекта или компонента не подключена в этом контексте. Подключение на клиенте не действует на сервере, и наоборот.
  • ❌ Новый COMОбъект падает с ошибкой создания объекта — библиотека не зарегистрирована на этом компьютере или зарегистрирована не той разрядности.
  • ❌ Метод не найден — у Native API имена методов задаёт сам разработчик компоненты (обычно русское и английское), у COM — только имя из библиотеки.

Все вызовы внешнего кода оборачивайте в Попытка … Исключение и пишите подробности в журнал регистрации:

Попытка
    Результат = Компонента.Выполнить(Параметр);
Исключение
    Инфо = ИнформацияОбОшибке();
    ЗаписьЖурналаРегистрации("ВнешняяКомпонента.Вызов", УровеньЖурналаРегистрации.Ошибка,,,
        ПодробноеПредставлениеОшибки(Инфо));
    ВызватьИсключение;
КонецПопытки;

Ошибки на стороне компоненты

Компонента Native API может сообщить об ошибке через метод AddError интерфейса IAddInDefBase. В зависимости от кода ошибки платформа либо выводит сообщение, либо вызывает исключение, которое перехватывается обычной Попытка.

Исключение C++, вылетевшее из компоненты наружу, платформа не перехватит. Ловите всё внутри каждого метода.

Отладка

  1. Соберите компоненту в отладочной конфигурации с файлами символов (.pdb).
  2. Запустите 1С и подключите компоненту хотя бы один раз.
  3. В Visual Studio выберите подключение к процессу: 1cv8c.exe или 1cv8.exe для клиентского кода, rphost.exe для серверного.
  4. Поставьте точку останова в методе и вызовите его из 1С.

Для серверной отладки удобнее файловая база: код &НаСервере тогда выполняется внутри процесса клиента, и искать нужный rphost не придётся.

Подключение отладчика к rphost.exe на рабочем сервере останавливает обработку запросов всех пользователей, чьи сеансы обслуживает этот процесс. Отлаживайте на тестовом сервере.

Как ускорить работу с внешней библиотекой

  • ⚡ Подключайте один раз. На клиенте храните объект компоненты в переменной модуля формы или модуля приложения, как в примере выше. Создание объекта на каждый вызов дорого.
  • 📦 Передавайте пачками. Тысяча вызовов по одному значению медленнее одного вызова с тысячей значений. Собирайте данные в строку JSON или ДвоичныеДанные и разбирайте внутри DLL.
  • 🔁 Сокращайте COM-обращения. Каждое чтение свойства COM-объекта — отдельный вызов. Значение, которое нужно в цикле, прочитайте один раз в переменную.
  • 🖥️ Переносите тяжёлое на сервер. Если компонента не работает с локальным оборудованием, вызывайте её на сервере: не придётся ставить её на клиенты, и не будет лишних клиент-серверных вызовов.
  • 🧵 Не держите поток. Долгую операцию внутри DLL лучше запускать в отдельном потоке компоненты и сообщать о завершении внешним событием (ExternalEvent), которое ловит процедура ОбработкаВнешнегоСобытия формы.

Примеры: что подключают к 1С через DLL

Работа с COM-объектами Windows. Самый частый практический случай — системные COM-библиотеки, которые уже зарегистрированы в Windows:

&НаКлиенте
Процедура ОткрытьПапкуВыгрузки(Команда)
    Оболочка = Новый COMОбъект("WScript.Shell");
    Оболочка.Run("explorer.exe ""C:\Выгрузка""", 1, Ложь);
КонецПроцедуры

Через Scripting.FileSystemObject так же получают свойства дисков, а через Excel.Application — управляют Excel, если он установлен.

Своя .NET-библиотека. Например, проверка подписи или расчёт по формуле банка. Пишете класс на C#, помечаете атрибутами COM, регистрируете RegAsm на сервере — и вызываете из общего модуля.

Компонента для оборудования. Драйверы оборудования для типовых конфигураций поставляются как внешние компоненты Native API. Подсистема подключаемого оборудования сама устанавливает и подключает их, поэтому код писать не нужно — достаточно добавить устройство в настройках.

Обёртка над чужой DLL. Есть SDK сканера отпечатков с функциями на C. Пишете компоненту Native API с двумя методами — Инициализировать и Сканировать, — которая внутри вызывает функции SDK через LoadLibrary и GetProcAddress. В 1С остаётся пять строк кода.

Какой способ подключения DLL выбрать?

Безопасность и ограничения внешних библиотек

Безопасный режим и профили безопасности

В безопасном режиме создание COM-объектов и подключение внешних компонент запрещено. Под это ограничение попадают внешние отчёты и обработки, которые конфигурация запускает в безопасном режиме, а также код, выполняемый внутри УстановитьБезопасныйРежим(Истина).

Если на кластере включены профили безопасности, разрешение на внешние компоненты и COM-классы задаётся в профиле. Без него код упадёт даже в обычном режиме.

Разрядность

32-битная DLL не загружается в 64-битный процесс. Это касается и клиента 1С, и рабочих процессов сервера.

  • для Native API включайте в архив сборки под обе разрядности;
  • для 32-битной COM-библиотеки на 64-битном сервере можно запускать её вне процесса через суррогатный процесс Windows dllhost.exe (настройка DllSurrogate или приложение COM+);
  • лучше всего — пересобрать библиотеку под x64.

Ограничения клиентов

Где выполняется кодNative APICOM
Тонкий и толстый клиент, WindowsДаДа
Тонкий клиент, LinuxДа, если в архиве есть .soНет
Веб-клиентДа, с расширением для работы с компонентами в браузереНет
Сервер на WindowsДаДа
Сервер на LinuxДа, если в архиве есть .soНет

Стабильность и доверие

Компонента работает в адресном пространстве процесса 1С. Ошибка в DLL на сервере роняет рабочий процесс rphost вместе со всеми сеансами, которые он обслуживает. Пользователи увидят разрыв соединения и потеряют несохранённые данные.

Отсюда простые правила:

  1. Подключайте только библиотеки из известного источника и с проверенной версией.
  2. Нестабильный или чужой код выносите в отдельный процесс: программу-посредник или COM-сервер вне процесса.
  3. Перед выкладкой на рабочий сервер прогоняйте компоненту под нагрузкой на копии базы.

Частые вопросы о DLL в 1С

Можно ли вызвать функцию WinAPI из 1С без своей компоненты?
Напрямую нет. Нужна внешняя компонента, COM-обёртка или программа-посредник, которая сделает вызов за 1С.
Нужно ли устанавливать компоненту на сервер?
Нет. На сервере компонента из макета подключается сразу через ПодключитьВнешнююКомпоненту. Установка нужна только на клиенте.
Где хранить DLL — в макете или в папке на диске?
В общем макете. Компонента обновляется вместе с конфигурацией и попадает на все рабочие серверы без ручного копирования. Путь к файлу на диске подходит только для разовой отладки.
Почему компонента работает в файловой базе, но не работает в клиент-серверной?
В клиент-серверной базе серверный код выполняется в rphost на другом компьютере. Там может не быть нужной разрядности DLL, регистрации COM или разрешения в профиле безопасности.
Можно ли подключить DLL, написанную на Delphi или C#?
Да. Из C# — как COM-объект через RegAsm. На Delphi пишут и COM-серверы, и компоненты Native API, если реализовать нужный интерфейс.