Как вызвать код внешней обработки во внешней базе через COM-соединение в 1С

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

При интеграции различных конфигураций 1С часто возникает необходимость выполнить определенный алгоритм на стороне принимающей базы (Базы 2) из отправляющей (Базы 1). Ситуация усложняется, если Базу 2 нельзя изменять (например, она находится на поддержке или закрыта для редактирования). В таких случаях отличным решением является использование справочника Дополнительные отчеты и обработки в Базе 2 и запуск хранящегося там кода через COM-соединение V83.ComConnector.

Однако при реализации этого механизма разработчики часто сталкиваются с неочевидными ошибками, такими как Метод объекта не обнаружен или сбоями при попытке прочитать файл обработки. В этой статье мы подробно разберем, почему возникают эти проблемы, как правильно организовать работу с временными файлами в контексте внешнего соединения и как оптимизировать этот процесс.

Разбор проблемы: почему возникает ошибка «Метод объекта не обнаружен»

Рассмотрим ситуацию, с которой столкнулся автор темы. Попытка вызвать экспортный метод внешней обработки завершалась аварийно. Давайте проанализируем первоначальный код:


V8 = Новый COMОбъект("V83.ComConnector");
СтрокаСоединения = Константы.СтрокаСоединенияСБазой2.Получить();
Соединение = V8.Connect(СтрокаСоединения);

ВнешняяОбработка = Соединение.Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("ИмяМоейОбработки");
ХранилищеВнешнейОбработки = ВнешняяОбработка.ХранилищеОбработки.Получить();

Если ХранилищеВнешнейОбработки = Неопределено Тогда
    Возврат;
КонецЕсли;

ИмяВременногоФайла = ПолучитьИмяВременногоФайла("epf");
ХранилищеВнешнейОбработки.Записать(ИмяВременногоФайла);
ВнешнийОтчет = Соединение.ВнешниеОбработки.Создать(ИмяВременногоФайла, Ложь);

Попытка
    ВнешнийОтчет.РеквизитФормыВЗначение("Объект").СведенияОВнешнейОбработке();
Исключение
    Сообщить(ОписаниеОшибки());
КонецПопытки;

В этом сценарии скрыты сразу три серьезные проблемы, которые приводят к ошибкам времени выполнения:

  1. Использование клиентских методов в COM-соединении. Метод РеквизитФормыВЗначение является методом управляемой формы. Внешнее COM-соединение всегда инициализирует невизуальный, исключительно серверный сеанс. В нем нет и не может быть объектов форм, поэтому любые попытки обратиться к форме или ее методам вызовут ошибку.
  2. Несоответствие контекстов файловой системы. Функция ПолучитьИмяВременногоФайла("epf"), вызванная в Базе 1, генерирует путь во временном каталоге локального компьютера или сервера Базы 1. Когда мы передаем этот путь в метод Соединение.ВнешниеОбработки.Создать(), COM-сервер пытается найти этот файл на своей стороне (на сервере Базы 2). Если базы физически находятся на разных серверах, файл просто не будет найден.
  3. Ошибочный вызов методов объекта. При программном создании внешней обработки через метод Создать() мы уже получаем полноценный объект внешней обработки. Никаких дополнительных преобразований контекста формы выполнять не требуется.

Решение проблемы: классический способ с использованием временного файла

Выяснив причины ошибок, скорректируем наш алгоритм. Мы должны сделать так, чтобы временный файл создавался в контексте принимающей базы данных (Базы 2), а вызов экспортного метода происходил непосредственно у объекта внешней обработки. Проанализируем исправленный код:


Процедура ВыполнитьКодВоВнешнейБазе()
    
    // Инициализируем COM-соединение к Базе 2
    V8 = Новый COMОбъект("V83.ComConnector");
    СтрокаСоединения = Константы.СтрокаСоединенияСБазой2.Получить();
    Соединение = V8.Connect(СтрокаСоединения);
    
    // Находим элемент справочника дополнительных обработок в Базе 2
    ВнешняяОбработкаОбъект = Соединение.Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("ИмяМоейОбработки");
    
    // Получаем двоичные данные файла обработки из хранилища значения
    ХранилищеВнешнейОбработки = ВнешняяОбработкаОбъект.ХранилищеОбработки.Получить();
    
    Если ХранилищеВнешнейОбработки = Неопределено Тогда
        ЗаписатьЛог("Файл обработки не найден в хранилище Базы 2.");
        Возврат;
    КонецЕсли;
    
    // КРИТИЧЕСКИ ВАЖНО: получаем имя временного файла в контексте Базы 2!
    ИмяВременногоФайла = Соединение.ПолучитьИмяВременногоФайла("epf");
    
    // Записываем двоичные данные в этот файл на стороне сервера Базы 2
    ХранилищеВнешнейОбработки.Записать(ИмяВременногоФайла);
    
    // Подключаем и создаем объект внешней обработки
    ВнешнийОбъект = Соединение.ВнешниеОбработки.Создать(ИмяВременногоФайла, Ложь);
    
    Попытка
        // Вызываем экспортную функцию из модуля объекта внешней обработки
        РезультатВыполнения = ВнешнийОбъект.СведенияОВнешнейОбработке();
        ЗаписатьЛог("Метод успешно выполнен. Результат: " + РезультатВыполнения);
    Исключение
        ЗаписатьЛог("Ошибка при вызове метода внешней обработки: " + ОписаниеОшибки());
    КонецПопытки;
    
    // Очищаем COM-объекты для освобождения памяти и лицензий
    ВнешнийОбъект = Неопределено;
    Соединение = Неопределено;
    V8 = Неопределено;
    
КонецПроцедуры

Важное примечание: Чтобы этот код отработал успешно, вызываемый метод (в нашем примере СведенияОВнешнейОбработке()) должен быть обязательно объявлен в Модуле объекта внешней обработки с ключевым словом Экспорт. Пример объявления метода внутри обработки:


Функция СведенияОВнешнейОбработке() Экспорт
    // Здесь располагается ваш алгоритм, который должен выполниться в Базе 2
    ВыполнитьНеобходимыеДействияНаСервере();
    Возврат "Успешно";
КонецФункции

Оптимизация: подключение обработки без записи файлов на диск

Рассмотренный выше классический способ полностью работоспособен, однако у него есть существенный недостаток — необходимость работы с файловой системой серверов. Это требует выделения прав на запись учетной записи, под которой запущен рабочий процесс 1С, а также несет в себе риски «засорения» временного каталога файлами .epf в случае аварийного завершения сессий.

Начиная с версии платформы 1С:Предприятие 8.3, мы можем полностью исключить работу с диском и подключить обработку напрямую из базы данных по навигационной ссылке. Рассмотрим, как это реализовать:


// Находим обработку в Базе 2
СсылкаНаОбработку = Соединение.Справочники.ДополнительныеОтчетыИОбработки.НайтиПоНаименованию("ИмяМоейОбработки");

// Получаем навигационную ссылку на реквизит хранилища значений
ПутьКДанным = Соединение.ПолучитьНавигационнуюСсылку(СсылкаНаОбработку, "ХранилищеОбработки");

// Подключаем внешнюю обработку во временное хранилище без записи на диск
ИмяПодключеннойОбработки = Соединение.ВнешниеОбработки.Подключить(ПутьКДанным);

// Создаем объект обработки по ее зарегистрированному имени
ВнешнийОбъект = Соединение.ВнешниеОбработки.Создать(ИмяПодключеннойОбработки);

// Вызываем нужный метод
ВнешнийОбъект.СведенияОВнешнейОбработке();

Этот способ гораздо быстрее, безопаснее и является стандартом разработки при использовании современных конфигураций.

Ограничения безопасности платформы 8.3 (Защита от опасных действий)

При использовании платформы версии 8.3.9 и выше при программном подключении внешних обработок вы можете столкнуться с защитным механизмом платформы — Защитой от опасных действий. В этом случае попытка подключения вернет ошибку доступа.

Чтобы обойти это ограничение, рассмотрим два пути решения:

  1. Отключение защиты для пользователя. Для учетной записи, под которой выполняется COM-подключение в Базе 2, необходимо в конфигураторе снять флажок Защита от опасных действий в свойствах пользователя.
  2. Программное отключение через БСП. Если База 2 разработана на основе Библиотеки Стандартных Подсистем (БСП), при подключении обработки можно передать специальный параметр защиты, отключающий проверки безопасности:

ПараметрыЗащиты = Соединение.ОбщегоНазначения.ОписаниеЗащитыБезПредупреждений();
ИмяПодключеннойОбработки = Соединение.ВнешниеОбработки.Подключить(ПутьКДанным, , Ложь, ПараметрыЗащиты);

Резюме и правила хорошего тона при интеграции через COM

Подводя итоги, сформулируем основные правила, которые позволят избежать ошибок при вызове кода через COM-соединение:

← На главную