Внешняя компонента 1С — библиотека, обычно на C++, которую платформа загружает в свой процесс и показывает встроенному языку как объект с методами, свойствами и событиями. Через неё 1С получает то, чего нет в платформе: системные API, нестандартные протоколы, быстрые алгоритмы, сторонние SDK. Ниже — полный цикл работы с ней на платформе 8.3, с кодом на каждом шаге. Сканеры и торговое оборудование разобраны отдельно, в статье про сканер штрихкода на Native API.
Примеры — для условной компоненты: ZIP в общем макете ДемоКомпонента, символическое имя Demo, объект Main. Её интерфейс:
Версия — свойство только для чтения;Таймаут — свойство для чтения и записи, в секундах;Обработать(Данные, ТекстОшибки) — функция, возвращает строку, ошибку пишет во второй параметр;ЗапуститьНаблюдение(Каталог) — функция, возвращает Истина и начинает слать внешние события о новых файлах;ОстановитьНаблюдение() — процедура.Жизненный цикл компоненты:
ПодключитьВнешнююКомпоненту или асинхронный аналог.Новый("AddIn.Demo.Main").Неопределено, а библиотека остаётся в памяти до завершения процесса.Native API — собственная технология 1С. Библиотека экспортирует несколько C-функций (GetClassNames, GetClassObject, DestroyObject), а её объекты реализуют интерфейс IComponentBase. В системе ничего не регистрируется: платформа берёт файл из макета и загружает сама. Поэтому одну компоненту собирают под Windows, Linux, macOS, мобильные ОС и браузеры.
COM досталась от 1С 7.7: DLL с интерфейсами IInitDone и ILanguageExtender. Она работает только в Windows, потому что COM — подсистема самой Windows: объект ищется по ProgID в реестре и создаётся системными библиотеками. В Linux, macOS и браузере этого механизма нет, поэтому COM не заработает на Linux-сервере, в веб-клиенте и на мобильной платформе.
| Признак | Native API | COM |
|---|---|---|
| ОС клиента и сервера | Windows, Linux, macOS | только Windows |
| Регистрация в системе | не нужна | regsvr32, реестр |
| Веб-клиент | да, при сборке под браузер | нет |
| Новые разработки | да | только сопровождение старых |
Технологию передают третьим параметром подключения: ТипВнешнейКомпоненты.Native или ТипВнешнейКомпоненты.COM. Указывайте её явно.
Стандартное место — общий макет с типом «Внешняя компонента» (в старых конфигурациях — «Двоичные данные»). В него загружают ZIP-архив: в корне лежат библиотеки под каждую платформу и файл MANIFEST.XML, по которому платформа выбирает нужную сборку. Корневой элемент манифеста — bundle с пространством имён http://v8.1c.ru/8.2/addin/bundle, внутри по элементу на сборку: <component os="Windows" path="DemoWin64.dll" type="native" arch="x86_64"/>.
| Атрибут | Значения | Смысл |
|---|---|---|
os | Windows, Linux, MacOS | операционная система |
arch | i386, x86_64 | разрядность процесса 1С, а не ОС |
type | native | технология |
path | имя файла | библиотека внутри архива |
Сборки для веб-клиента описываются там же, с указанием браузера. Нет подходящей строки — подключение вернёт Ложь. Кроме общего макета, Местоположение принимает макет объекта ("Обработка.Загрузка.Макет.Компонента"), адрес во временном хранилище и путь к файлу (кроме веб-клиента).
Самый короткий вариант. Работает в тонком и толстом клиенте, если в свойствах конфигурации «Режим использования синхронных вызовов расширений платформы и внешних компонент» не стоит «Не использовать».
// Общий модуль ДемоКомпонентаКлиент (флаг «Клиент (управляемое приложение)»).
// Синхронный вариант: режим использования синхронных вызовов расширений
// платформы и внешних компонент — «Использовать».
Функция Компонента() Экспорт
ОбъектКомпоненты = ПараметрыПриложения.Получить("ДемоКомпонента.Объект");
Если ОбъектКомпоненты <> Неопределено Тогда
Возврат ОбъектКомпоненты; // уже создан в этом сеансе
КонецЕсли;
Местоположение = "ОбщийМакет.ДемоКомпонента";
Подключена = ПодключитьВнешнююКомпоненту(Местоположение, "Demo", ТипВнешнейКомпоненты.Native);
Если Не Подключена Тогда
// Первый запуск на этом компьютере: диалог установки,
// библиотека сохраняется в профиле пользователя
УстановитьВнешнююКомпоненту(Местоположение);
Подключена = ПодключитьВнешнююКомпоненту(Местоположение, "Demo", ТипВнешнейКомпоненты.Native);
КонецЕсли;
Если Не Подключена Тогда
ВызватьИсключение НСтр("ru = 'Не удалось подключить внешнюю компоненту Demo на клиенте.'");
КонецЕсли;
ОбъектКомпоненты = Новый("AddIn.Demo.Main");
ПараметрыПриложения.Вставить("ДемоКомпонента.Объект", ОбъектКомпоненты);
Возврат ОбъектКомпоненты;
КонецФункции
ПараметрыПриложения — клиентское соответствие на весь сеанс: объект создаётся один раз и доступен из любой формы. В реквизит формы его не положить.ПодключитьВнешнююКомпоненту возвращает Булево: если библиотеку загрузить не удалось, исключения не будет, поэтому результат проверяем явно.УстановитьВнешнююКомпоненту срабатывает только при первом запуске на компьютере: платформа покажет диалог и сохранит библиотеку в профиле пользователя."AddIn.Demo.Main" имя Demo задали мы при подключении, а Main объявила сама компонента.В веб-клиенте и в конфигурациях на БСП, где синхронные вызовы запрещены, нужны асинхронные методы:
| Действие | Синхронно | С оповещением | Асинх (8.3.18+) |
|---|---|---|---|
| Установка, только клиент | УстановитьВнешнююКомпоненту | НачатьУстановкуВнешнейКомпоненты | УстановитьВнешнююКомпонентуАсинх |
| Подключение | ПодключитьВнешнююКомпоненту | НачатьПодключениеВнешнейКомпоненты | ПодключитьВнешнююКомпонентуАсинх |
Вариант на оповещениях работает и до 8.3.18:
// Тот же общий модуль ДемоКомпонентаКлиент. Вариант на оповещениях:
// работает в веб-клиенте и при запрете синхронных вызовов.
// Вызов из формы:
// ДемоКомпонентаКлиент.НачатьПолучениеКомпоненты(Новый ОписаниеОповещения("ПослеПолучения", ЭтотОбъект));
// В ПослеПолучения(ОбъектКомпоненты, ДополнительныеПараметры) придёт объект или Неопределено.
Процедура НачатьПолучениеКомпоненты(ОповещениеОЗавершении) Экспорт
ОбъектКомпоненты = ПараметрыПриложения.Получить("ДемоКомпонента.Объект");
Если ОбъектКомпоненты <> Неопределено Тогда
ВыполнитьОбработкуОповещения(ОповещениеОЗавершении, ОбъектКомпоненты);
Возврат;
КонецЕсли;
Контекст = Новый Структура;
Контекст.Вставить("Местоположение", "ОбщийМакет.ДемоКомпонента");
Контекст.Вставить("ОповещениеОЗавершении", ОповещениеОЗавершении);
Контекст.Вставить("УстановкаБыла", Ложь);
НачатьПодключениеДемо(Контекст);
КонецПроцедуры
Процедура НачатьПодключениеДемо(Контекст)
Оповещение = Новый ОписаниеОповещения("ПослеПодключенияДемо", ДемоКомпонентаКлиент, Контекст);
НачатьПодключениеВнешнейКомпоненты(Оповещение, Контекст.Местоположение, "Demo",
ТипВнешнейКомпоненты.Native);
КонецПроцедуры
Процедура ПослеПодключенияДемо(Подключено, Контекст) Экспорт
Если Подключено Тогда
ОбъектКомпоненты = Новый("AddIn.Demo.Main");
ПараметрыПриложения.Вставить("ДемоКомпонента.Объект", ОбъектКомпоненты);
ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, ОбъектКомпоненты);
ИначеЕсли Не Контекст.УстановкаБыла Тогда
Контекст.УстановкаБыла = Истина;
Оповещение = Новый ОписаниеОповещения("ПослеУстановкиДемо", ДемоКомпонентаКлиент, Контекст,
"ПриОшибкеУстановкиДемо", ДемоКомпонентаКлиент);
НачатьУстановкуВнешнейКомпоненты(Оповещение, Контекст.Местоположение);
Иначе
ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Неопределено);
КонецЕсли;
КонецПроцедуры
Процедура ПослеУстановкиДемо(Контекст) Экспорт
НачатьПодключениеДемо(Контекст); // вторая попытка, уже после установки
КонецПроцедуры
Процедура ПриОшибкеУстановкиДемо(ИнформацияОбОшибке, СтандартнаяОбработка, Контекст) Экспорт
СтандартнаяОбработка = Ложь; // сообщение покажет вызывающая форма
ВыполнитьОбработкуОповещения(Контекст.ОповещениеОЗавершении, Неопределено);
КонецПроцедуры
ЭтотОбъект, поэтому в ОписаниеОповещения передаём сам модуль ДемоКомпонентаКлиент, а обработчики делаем экспортными.УстановкаБыла не даёт зациклиться на «подключить — установить», если сборки под эту платформу в архиве нет.ИнформацияОбОшибке и СтандартнаяОбработка.С 8.3.18 тот же сценарий пишется линейно через Ждать. Метод компоненты в примере вызывается через НачатьВызов<ИмяМетода> — такой код работает и в веб-клиенте.
// Платформа 8.3.18 и выше. Общий модуль ДемоКомпонентаКлиент.
Асинх Функция КомпонентаАсинх() Экспорт
ОбъектКомпоненты = ПараметрыПриложения.Получить("ДемоКомпонента.Объект");
Если ОбъектКомпоненты <> Неопределено Тогда
Возврат ОбъектКомпоненты;
КонецЕсли;
Местоположение = "ОбщийМакет.ДемоКомпонента";
Подключена = Ждать ПодключитьВнешнююКомпонентуАсинх(Местоположение, "Demo", ТипВнешнейКомпоненты.Native);
Если Не Подключена Тогда
Попытка
Ждать УстановитьВнешнююКомпонентуАсинх(Местоположение);
Исключение
Возврат Неопределено; // отказ от установки или нет сборки под эту платформу
КонецПопытки;
Подключена = Ждать ПодключитьВнешнююКомпонентуАсинх(Местоположение, "Demo", ТипВнешнейКомпоненты.Native);
КонецЕсли;
Если Подключена Тогда
ОбъектКомпоненты = Новый("AddIn.Demo.Main");
ПараметрыПриложения.Вставить("ДемоКомпонента.Объект", ОбъектКомпоненты);
КонецЕсли;
Возврат ОбъектКомпоненты; // объект или Неопределено
КонецФункции
// Модуль формы обработки с реквизитами ИсходныеДанные и Результат (Строка).
&НаКлиенте
Асинх Процедура КомандаОбработать(Команда)
ОбъектКомпоненты = Ждать ДемоКомпонентаКлиент.КомпонентаАсинх();
Если ОбъектКомпоненты = Неопределено Тогда
ПоказатьПредупреждение(, НСтр("ru = 'Компонента Demo недоступна на этом рабочем месте.'"));
Возврат;
КонецЕсли;
// Асинхронный вызов метода Обработать(Данные, ТекстОшибки)
Оповещение = Новый ОписаниеОповещения("ПослеВызоваОбработать", ЭтотОбъект);
ОбъектКомпоненты.НачатьВызовОбработать(Оповещение, Объект.ИсходныеДанные, "");
КонецПроцедуры
&НаКлиенте
Процедура ПослеВызоваОбработать(РезультатВызова, ПараметрыВызова, ДополнительныеПараметры) Экспорт
ТекстОшибки = ПараметрыВызова[1]; // второй параметр компонента заполнила по ссылке
Если ЗначениеЗаполнено(ТекстОшибки) Тогда
ПоказатьПредупреждение(, ТекстОшибки);
Возврат;
КонецЕсли;
Объект.Результат = РезультатВызова;
КонецПроцедуры
Асинх Функция возвращает Обещание, поэтому вызывающая процедура тоже объявлена Асинх и получает объект через Ждать.Ждать становится исключением — отсюда Попытка вокруг УстановитьВнешнююКомпонентуАсинх.НачатьВызовОбработать — асинхронная форма метода Обработать: префикс НачатьВызов плюс имя метода, первым параметром — оповещение. Для свойств есть НачатьПолучение<ИмяСвойства> и НачатьУстановку<ИмяСвойства>.ПараметрыВызова приходит массив параметров после вызова: так читаются значения, которые компонента вернула по ссылке.В 8.3.27 анонсирован ещё и асинхронный конструктор объекта — СоздатьОбъектВнешнейКомпонентыАсинх.
На сервере установка не нужна: платформа сама распакует библиотеку во временный каталог при первом подключении в рабочем процессе. Нужны сборка под ОС и разрядность сервера и право службы 1С писать в этот каталог. Синхронные вызовы здесь разрешены всегда.
// Общий модуль ДемоКомпонентаВызовСервера (флаги «Сервер» и «Вызов сервера»).
Функция Обработать(ИсходныеДанные) Экспорт
ОбъектКомпоненты = НовыйОбъектКомпоненты();
ОбъектКомпоненты.Таймаут = 30; // свойство для записи
ВерсияКомпоненты = ОбъектКомпоненты.Версия; // свойство только для чтения
ТекстОшибки = "";
Попытка
Результат = ОбъектКомпоненты.Обработать(ИсходныеДанные, ТекстОшибки);
Исключение
ЗаписьЖурналаРегистрации("ДемоКомпонента.Ошибка", УровеньЖурналаРегистрации.Ошибка, , ,
ПодробноеПредставлениеОшибки(ИнформацияОбОшибке()));
ВызватьИсключение;
КонецПопытки;
Если ЗначениеЗаполнено(ТекстОшибки) Тогда
ВызватьИсключение СтрШаблон(НСтр("ru = 'Компонента Demo %1: %2'"), ВерсияКомпоненты, ТекстОшибки);
КонецЕсли;
Возврат Результат;
КонецФункции
Функция НовыйОбъектКомпоненты()
// В процессе, где компонента уже загружена, повторное подключение проходит быстро
Подключена = ПодключитьВнешнююКомпоненту("ОбщийМакет.ДемоКомпонента", "Demo", ТипВнешнейКомпоненты.Native);
Если Не Подключена Тогда
Информация = Новый СистемнаяИнформация;
ВызватьИсключение СтрШаблон(
НСтр("ru = 'Не удалось подключить внешнюю компоненту Demo на сервере (%1, платформа %2).'"),
Информация.ТипПлатформы, Информация.ВерсияПриложения);
КонецЕсли;
Возврат Новый("AddIn.Demo.Main");
КонецФункции
ТекстОшибки передан по ссылке: компонента записывает в него текст, и переменная меняется.ВызватьИсключение без параметров.ТипПлатформы в тексте ошибки сразу показывает, какой сборки не хватает: Windows_x86_64, Linux_x86_64 и т. д.У внешней обработки своих общих макетов нет, поэтому ZIP кладут в макет самой обработки и подключают через временное хранилище:
// Модуль объекта внешней обработки. ZIP компоненты лежит в её макете «Компонента»
// с типом «Двоичные данные».
Функция ОбработатьДанные(ИсходныеДанные) Экспорт
Адрес = ПоместитьВоВременноеХранилище(ПолучитьМакет("Компонента"));
Если Не ПодключитьВнешнююКомпоненту(Адрес, "DemoExt", ТипВнешнейКомпоненты.Native) Тогда
ВызватьИсключение НСтр("ru = 'Не удалось подключить внешнюю компоненту из макета обработки.'");
КонецЕсли;
ОбъектКомпоненты = Новый("AddIn.DemoExt.Main");
ТекстОшибки = "";
Результат = ОбъектКомпоненты.Обработать(ИсходныеДанные, ТекстОшибки);
Если ЗначениеЗаполнено(ТекстОшибки) Тогда
ВызватьИсключение ТекстОшибки;
КонецЕсли;
Возврат Результат;
КонецФункции
// Модуль формы этой обработки
&НаКлиенте
Процедура КомандаОбработать(Команда)
ОбработатьНаСервере();
КонецПроцедуры
&НаСервере
Процедура ОбработатьНаСервере()
Обработка = РеквизитФормыВЗначение("Объект");
Объект.Результат = Обработка.ОбработатьДанные(Объект.ИсходныеДанные);
КонецПроцедуры
ПоместитьВоВременноеХранилище без идентификатора формы хранит данные до конца серверного вызова — подключению этого хватает.DemoExt не пересечётся с компонентами самой конфигурации.Компонента сама сообщает 1С о происшествиях: вызывает ExternalEvent с тремя строками — источник, событие, данные. На клиенте их получают открытые формы с обработчиком ВнешнееСобытие и процедура ОбработкаВнешнегоСобытия модуля управляемого приложения. На сервере внешние события не обрабатываются.
// Модуль формы. Компонента шлёт ExternalEvent("DemoAddIn", "ФайлСоздан", <путь к файлу>).
// Обработчик ВнешнееСобытие назначьте в событиях формы. НовыеФайлы — реквизит формы
// (СписокЗначений), КаталогОбмена — реквизит обработки.
&НаКлиенте
Перем Наблюдатель;
&НаКлиенте
Процедура ВключитьНаблюдение(Команда)
Наблюдатель = ДемоКомпонентаКлиент.Компонента(); // синхронный вариант из первого листинга
Если Не Наблюдатель.ЗапуститьНаблюдение(Объект.КаталогОбмена) Тогда
ВызватьИсключение НСтр("ru = 'Компонента не смогла начать наблюдение за каталогом.'");
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВнешнееСобытие(Источник, Событие, Данные)
// Источник — строка из ExternalEvent, а не имя "Demo" из ПодключитьВнешнююКомпоненту
Если Источник <> "DemoAddIn" Тогда
Возврат; // события других компонент не трогаем
КонецЕсли;
Если Событие = "ФайлСоздан" Тогда
НовыеФайлы.Добавить(Данные);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ПриЗакрытии(ЗавершениеРаботы)
Если Наблюдатель <> Неопределено Тогда
Наблюдатель.ОстановитьНаблюдение();
Наблюдатель = Неопределено;
КонецЕсли;
КонецПроцедуры
// Модуль управляемого приложения: событие приходит и при закрытых формах
Процедура ОбработкаВнешнегоСобытия(Источник, Событие, Данные)
Если Источник = "DemoAddIn" И Событие = "Ошибка" Тогда
ПоказатьОповещениеПользователя(НСтр("ru = 'Demo: ошибка наблюдения'"), , Данные);
КонецЕсли;
КонецПроцедуры
Источник берите из описания компоненты: это её строка, а не символическое имя из подключения.SetEventBufferDepth.ПодключитьВнешнююКомпоненту вернула Ложь, — причину платформа не сообщает. Проверьте: есть ли в манифесте строка под ОС и разрядность процесса, установлена ли компонента на клиенте, хватает ли системных библиотек (Visual C++ Redistributable в Windows, вывод ldd в Linux).i386 и x86_64. COM-DLL тоже должна совпадать по разрядности с процессом 1С: 32-разрядную не увидит 64-разрядный rphost, даже если regsvr32 отработал без ошибок.noexec — библиотека не загрузится. COM-компонента на Linux не работает вообще.НачатьПодключениеВнешнейКомпоненты или Асинх-варианты и НачатьВызов…. В браузере должно стоять расширение для работы с 1С:Предприятием, а в манифесте — сборка под этот браузер.Нет: методы установки работают только на клиенте. Сервер распаковывает библиотеку из макета сам, нужна лишь сборка под его ОС и разрядность.
Нет. Подключение и объекты живут только в том процессе, где созданы: объект нельзя вернуть с сервера, сохранить в реквизите формы или во временном хранилище. На клиенте подключайте компоненту отдельно.
Для отладки передайте в Местоположение полный путь к файлу на диске — макет не нужен, но в веб-клиенте так нельзя. Пользователям файл доставляют через макет, справочник или временное хранилище, как во внешней обработке выше.
С версии 8.3.21.1302 компоненту можно запустить в отдельном процессе: тип подключения задаёт необязательный параметр ПодключитьВнешнююКомпоненту. Если изолированная компонента упадёт, клиент или рабочий процесс сервера продолжат работу. Плата — межпроцессный обмен при каждом вызове; компонента должна поддерживать этот режим.
Если компоненту нужно написать с нуля, собрать под Windows и Linux или встроить в типовую конфигурацию без синхронных вызовов, быстрее поручить это исполнителю — см. услуги по доработке 1С. Опишите библиотеку, версию платформы и клиенты на странице «Разместить задание», и исполнители оценят сроки и стоимость.
Станьте частью сообщества!
Войдите или зарегистрируйтесь, и вы сможете участвовать в обсуждениях.