Внешняя DLL и 1С:Предприятие 8.3: от регистрации до первого вызова

· 9 мин

Содержание

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

Отсюда и большинство проблем: библиотека лежит в папке, путь указан верно, а 1С отвечает Недопустимая строка с указанием класса или Тип не определен. Ниже разобрано, как выбрать интерфейс, зарегистрировать библиотеку с нужной разрядностью, написать код подключения и найти причину, если что-то не заработало.

COM или Native API: какой способ подключения DLL выбрать

Решение зависит от трёх вещей: где будет работать код (клиент или сервер), на какой ОС и есть ли у вас исходники библиотеки.

КритерийCOM-объектВнешняя компонента Native API
ОСТолько WindowsWindows, Linux, macOS (своя сборка под каждую)
Регистрация в системеОбязательна (regsvr32, regasm)Не нужна, платформа сама распаковывает и загружает
Где хранитсяНа диске каждого компьютераВ макете конфигурации, внешней обработки или расширения
Веб-клиентНетДа, через расширение браузера и сборку под него
РазработкаЛюбой язык с поддержкой COM: C++, C#, DelphiC++ по интерфейсу Native API (IComponentBase)
Передача массивовCOMSafeArrayТолько через строку (JSON, XML) или двоичные данные
Готовые библиотекиМногие драйверы и SDK уже COMНужно писать обёртку

Практическое правило:

  • 🔹 есть готовый COM-сервер от производителя (сканер, ККТ, SDK банка) и только Windows — берите COM;
  • 🔹 библиотека ваша, нужен Linux-сервер или веб-клиент — пишите компоненту Native API;
  • 🔹 есть только DLL с «голыми» функциями на C — нужна тонкая обёртка. Быстрее всего на C# с COM-видимым классом, переносимее всего на C++ под Native API.

Технология COM в 1С — это «старый» путь, но для разовой интеграции на Windows он остаётся самым коротким. Native API выигрывает, когда базу тиражируют или переносят на Linux.

Регистрация COM-библиотеки в Windows: regsvr32, regasm и разрядность

COM-объект 1С ищет по ProgID в реестре Windows. Если библиотека не зарегистрирована, никакой код её не найдёт.

Классическая COM-DLL (C++, Delphi)

  1. Скопируйте DLL и все её зависимости в постоянную папку, например C:\Program Files\MyLib\. Не регистрируйте из «Загрузок» и временных папок.
  2. Запустите командную строку от имени администратора.
  3. Выполните регистрацию подходящей утилитой:
:: 64-битная DLL на 64-битной Windows
C:\Windows\System32\regsvr32.exe "C:\Program Files\MyLib\MyLib.dll"

:: 32-битная DLL на 64-битной Windows
C:\Windows\SysWOW64\regsvr32.exe "C:\Program Files (x86)\MyLib\MyLib.dll"

:: Отменить регистрацию
C:\Windows\SysWOW64\regsvr32.exe /u "C:\Program Files (x86)\MyLib\MyLib.dll"

Путаница с папками — классика: System32 на 64-битной системе содержит 64-битные утилиты, а SysWOW64 — 32-битные.

.NET-сборка (C#)

Сборку .NET регистрируют не regsvr32, а RegAsm.exe нужной разрядности:

:: для 32-битного клиента 1С
C:\Windows\Microsoft.NET\Framework\v4.0.30319\RegAsm.exe MyLib.dll /codebase /tlb

:: для 64-битного клиента или сервера 1С
C:\Windows\Microsoft.NET\Framework64\v4.0.30319\RegAsm.exe MyLib.dll /codebase /tlb

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

Главное правило разрядности

Разрядность DLL должна совпадать с разрядностью процесса 1С, который её создаёт. 32-битный тонкий клиент не загрузит 64-битную библиотеку, и наоборот. Ошибка при этом выглядит как «класс не зарегистрирован», хотя регистрация прошла успешно.

Проверить разрядность клиента просто: в окне Справка → О программе указано, 32- или 64-разрядная версия запущена. Для сервера смотрите, из какой папки запущен ragent.exe: Program Files или Program Files (x86).

Код подключения DLL в 1С: COMОбъект и ПодключитьВнешнююКомпоненту

Создание COM-объекта

&НаКлиенте
Процедура ВызватьБиблиотеку(Команда)

    Попытка
        Калькулятор = Новый COMОбъект("MyLib.Calc");
    Исключение
        Сообщить("Не удалось создать COM-объект: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;

    Результат = Калькулятор.Сложить(2, 3);
    Сообщить("Результат: " + Формат(Результат, "ЧГ=0"));

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

Методы и свойства COM-объекта вызываются по именам, которые задал разработчик библиотеки. Регистр букв не важен. Список доступных методов смотрите в документации к DLL или в библиотеке типов (.tlb) через просмотрщик OLE/COM.

Подключение внешней компоненты Native API

Компонента хранится в общем макете с типом «Внешняя компонента» (ZIP-архив с MANIFEST.XML и сборками под разные ОС). Подключение в коде:

&НаСервере
Функция ПолучитьКомпоненту()

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

    Если Не Подключено Тогда
        ВызватьИсключение "Внешняя компонента не подключена";
    КонецЕсли;

    Возврат Новый("AddIn.Штрихкод.Генератор");

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

Схема имени объекта: AddIn.<имя, указанное при подключении>.<имя класса из компоненты>. Имя класса возвращает функция GetClassNames внутри DLL, его даёт разработчик.

ПодключитьВнешнююКомпоненту() не выбрасывает исключение при неудаче, а возвращает Ложь. Проверяйте результат, иначе ошибка всплывёт строкой ниже как Тип не определен (AddIn.Штрихкод.Генератор).

Подключение на клиенте: асинхронные методы

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

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

    Место = "ОбщийМакет.КомпонентаШтрихкод";

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

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

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

Схема «попробовать подключить → установить → подключить повторно» избавляет пользователя от лишнего диалога установки при каждом запуске.

Внешняя компонента в макете обработки и в расширении

Не всегда можно менять основную конфигурацию. Компоненту можно положить в макет внешней обработки или расширения.

Внешняя обработка (.epf)

У внешней обработки нет общих макетов, путь вида ОбщийМакет.Имя не сработает. Рабочий приём — поместить макет во временное хранилище и подключать по адресу:

&НаСервере
Функция АдресКомпоненты()
    Обработка = РеквизитФормыВЗначение("Объект");
    Возврат ПоместитьВоВременноеХранилище(Обработка.ПолучитьМакет("Компонента"), УникальныйИдентификатор);
КонецФункции

&НаКлиенте
Асинх Процедура Подключить(Команда)
    Адрес = АдресКомпоненты();
    Подключено = Ждать ПодключитьВнешнююКомпонентуАсинх(Адрес, "Штрихкод", ТипВнешнейКомпоненты.Native);
    // далее как в основной конфигурации
КонецПроцедуры

Макет в обработке создаётся с типом «Двоичные данные» и содержит тот же ZIP-архив компоненты.

Расширение конфигурации

В расширении (доступны с платформы 8.3.6) добавьте собственный общий макет с компонентой. Обращение к нему такое же: "ОбщийМакет.ИмяМакетаВРасширении". Основная конфигурация при этом не меняется, обновления типовой встают без конфликтов.

Если расширение или обработка работает в безопасном режиме, подключение внешних компонент и создание COM-объектов будет запрещено. Нужно снять флаг безопасного режима у расширения или разрешить компоненты в профиле безопасности. Делайте это только для кода, которому доверяете.

Передача данных между 1С и DLL: типы, массивы, события

Как преобразуются типы

Тип 1СCOMNative API
ЧислоVT_I4, VT_R8 (целое или дробное)int32, double
СтрокаBSTRWCHAR_T* (UTF-16)
БулевоVT_BOOLbool
ДатаVT_DATEструктура tm
ДвоичныеДанныемассив байтовpstrVal с длиной (blob)
МассивCOMSafeArrayне передаётся, только сериализацией

Для Native API строки и двоичные данные, которые компонента возвращает в 1С, нужно выделять через менеджер памяти платформы (IMemoryManager::AllocMemory). Обычный new или malloc приводит к утечкам или падению клиента.

Массивы через COMSafeArray

Параметры = Новый COMSafeArray("VT_VARIANT", 3);
Параметры.SetValue(0, "Склад");
Параметры.SetValue(1, 150);
Параметры.SetValue(2, Истина);

Ответ = Объект.ОбработатьПакет(Параметры);

// Если DLL вернула SafeArray — переводим в массив 1С
МассивОтвета = Ответ.Выгрузить();

Индексы SetValue начинаются с нуля, размер задаётся при создании. Метод Выгрузить() превращает COMSafeArray в обычный Массив.

Сложные структуры в Native API

Передавайте их строкой JSON: в 1С собирайте Структуру и сериализуйте через ЗаписатьJSON(), в DLL разбирайте любой библиотекой JSON. Обратно — так же. Это проще и надёжнее, чем десяток свойств компоненты.

Внешние события

Компонента может сама «дёргать» 1С, например, когда сканер считал код. В DLL вызывается ExternalEvent, в форме срабатывает обработчик:

&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
    Если Источник = "Штрихкод" И Событие = "Считан" Тогда
        ОбработатьШтрихкод(Данные);
    КонецЕсли;
КонецПроцедуры

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

Код с &НаСервере выполняется в рабочем процессе rphost, а не на компьютере пользователя. Отсюда три отличия.

  1. Регистрация на каждом рабочем сервере. COM-DLL регистрируется на всех серверах кластера, где может оказаться сеанс. Native-компонента из макета распаковывается сама.
  2. Разрядность сервера. Сервер 1С обычно 64-битный. Если производитель дал только 32-битную COM-DLL, есть приём: запустить её вне процесса через суррогат dllhost.exe. Для этого в разделе реестра HKEY_CLASSES_ROOT\AppID\{GUID класса} создают строковый параметр DllSurrogate с пустым значением, а в разделе CLSID\{GUID} указывают AppID. Тогда 64-битный процесс 1С создаёт объект через COM-маршалинг.
  3. Права учётной записи службы. Служба 1С работает от отдельного пользователя (часто USR1CV8). Ему нужны права на чтение папки с DLL, а для внешнего COM-сервера — разрешения запуска и активации в dcomcnfg.

На Linux-сервере COM нет вообще. Работает только Native API со сборкой .so в архиве компоненты.

Если компонента упадёт с исключением внутри DLL, вместе с ней упадёт рабочий процесс сервера и оборвутся сеансы пользователей на этом процессе. Тестируйте новую компоненту на копии базы и отдельном сервере, а не в рабочем кластере в разгар дня.

С платформы 8.3.21 у ПодключитьВнешнююКомпоненту есть параметр типа подключения: компоненту можно запустить изолированно, в отдельном процессе. Сбой DLL тогда не роняет основной процесс 1С. Для новых и непроверенных компонент это разумный выбор.

Почему DLL не подключается: диагностика и логирование

Начните с текста ошибки: по нему почти всегда видно, на каком этапе сломалось.

Диагностика: выберите симптом

Логирование со стороны 1С

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

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

Своё имя события упрощает фильтр: в журнале регистрации отбираете по «Интеграция.ВнешняяDLL» и видите только эти сбои.

Логирование со стороны DLL

  • 📝 пишите в текстовый лог входные параметры и коды возврата каждого метода;
  • 📝 для Native API используйте AddError у интерфейса платформы: сообщение придёт в 1С как обычное исключение с понятным текстом;
  • 🔍 если DLL не грузится вовсе, запустите Process Monitor от Microsoft с фильтром по имени процесса (1cv8c.exe или rphost.exe). Строки NAME NOT FOUND покажут, какую зависимость система не нашла.

Частые вопросы

Можно ли вызвать функцию из обычной DLL без COM и Native API?
Нет, встроенный язык 1С не умеет вызывать экспортируемые функции произвольной DLL. Нужна обёртка: COM-класс или внешняя компонента.
Нужно ли регистрировать DLL при каждом обновлении конфигурации?
COM-библиотеку — нет, регистрация живёт в реестре Windows до удаления или переустановки DLL. Native-компоненту из макета регистрировать не нужно вовсе.
Работает ли COM-объект в веб-клиенте?
Нет. В веб-клиенте доступны только внешние компоненты Native API со сборкой под браузерное расширение.
Как обновить версию компоненты в макете?
Замените двоичные данные макета новым архивом и обновите конфигурацию. На клиентах, где была установлена старая версия, платформа установит новую при следующем подключении с установкой.
Можно ли держать одну DLL и для 32-, и для 64-битного клиента?
Одну — нет. В архив Native-компоненты кладут две сборки и описывают обе в MANIFEST.XML. Для COM регистрируют две DLL разной разрядности под одним ProgID.