Как обратиться к экспортной процедуре 1С из кода и внешней обработки

· 10 мин

Содержание

Чтобы вызвать процедуру из другого модуля, её объявляют с ключевым словом Экспорт. Без него метод виден только внутри своего модуля. Дальше обращение зависит от того, где процедура лежит: в общем модуле её вызывают через ИмяМодуля.ИмяПроцедуры(...), в файле .epf — через менеджер ВнешниеОбработки, а в другой информационной базе — через COM-соединение V83.COMConnector.

Разберём все три сценария: от простого обращения внутри конфигурации до вызова экспортной процедуры в чужой базе по COM. С синтаксисом, передачей параметров и типичными ошибками, на которые уходит больше всего времени.

Что делает ключевое слово «Экспорт» и откуда видна процедура

Экспорт ставится в заголовке процедуры или функции и открывает её для вызова извне модуля:

Процедура ПересчитатьОстатки(Склад, ДатаРасчёта) Экспорт
    // тело процедуры
КонецПроцедуры

Где объявлена процедура — оттуда и зависит способ обращения:

  • 📦 Общий модуль. Вызов по имени модуля: РаботаСОстатками.ПересчитатьОстатки(Склад, Дата). Это основной способ переиспользовать код внутри конфигурации.
  • 🧾 Модуль объекта (документа, обработки, справочника). Экспортный метод доступен через ссылку на объект: ДокументОбъект.Провести() — после того как объект получен.
  • 🗂 Модуль формы. Экспортные методы формы видны тем, кто получил эту форму программно.

У общего модуля важны флаги в его свойствах: Клиент (управляемое приложение), Сервер, Вызов сервера. Если процедура должна работать на сервере, а флаг Сервер снят — вызов просто не скомпилируется. Это первое, что стоит проверить, когда «процедура не находится».

Для вызова внутри конфигурации ничего регистрировать не нужно — компилятор видит все модули. Сложности начинаются, когда код лежит во внешнем файле или в другой базе.

Вызов экспортной процедуры из внешней обработки

Внешняя обработка (файл .epf) подключается во время работы и несёт собственный модуль объекта. Экспортные процедуры этого модуля вызывают так:

Обработка = ВнешниеОбработки.Создать("C:\Обмен\Пересчёт.epf");
Обработка.ПересчитатьОстатки("Основной склад", ТекущаяДата());

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

Разберём параметры Создать по порядку:

  1. Путь к файлу .epf — абсолютный путь на том компьютере, где исполняется код (на клиенте или на сервере — в зависимости от контекста).
  2. Безопасный режим — второй параметр. Значение Истина запускает обработку с ограничениями: без доступа к файловой системе, COM и внешним компонентам. Для доверенного кода ставят Ложь.
  3. Уникальный ключ — третий параметр, нужен, если одну обработку подключают несколько раз и важно различать экземпляры.

Для внешнего отчёта (.erf) всё аналогично, только менеджер другой — ВнешниеОтчёты.Создать. Экспортные процедуры его модуля объекта вызываются так же, через полученный объект.

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

Частая ошибка на этом шаге — вызвать экспортную процедуру формы обработки, а не её модуля объекта. Создать возвращает именно объект; методы формы доступны только после того, как форма получена и открыта, и это уже другой сценарий.

Путь к .epf на сервере и на клиенте — разные файловые системы. Если код выполняется на сервере (&НаСервере), файл должен лежать там, куда у сервера есть доступ, а не на машине пользователя.

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

Обращение к процедурам другой базы через COM-соединение

Когда процедура живёт в отдельной информационной базе, её вызывают через внешнее соединение. Схема такая: создаём COM-объект V83.COMConnector, подключаемся к базе методом Connect, получаем ссылку на контекст этой базы и дальше работаем с её объектами и общими модулями.

Коннектор = Новый COMОбъект("V83.COMConnector");
Соединение = Коннектор.Connect(
    "Srvr=""srv-1c"";Ref=""buh"";Usr=""Обмен"";Pwd=""пароль""");
Соединение.РаботаСОстатками.ПересчитатьОстатки("Основной склад", ТекущаяДата());

Строка подключения различается для файловой и клиент-серверной базы:

БазаСтрока соединения
ФайловаяFile="D:\Bases\Buh";Usr="Обмен";Pwd="пароль"
Клиент-сервернаяSrvr="srv-1c";Ref="buh";Usr="Обмен";Pwd="пароль"

В коде 1С кавычки внутри строки удваиваются, поэтому в примере выше они идут парами. Параметры Usr и Pwd — логин и пароль пользователя той базы, под которым выполняется соединение.

Главный практический шаг, про который часто забывают: библиотеку comcntr.dll нужно зарегистрировать в системе. Без регистрации создание объекта V83.COMConnector падает с ошибкой «Класс не зарегистрирован». Регистрируют так, из командной строки от имени администратора:

regsvr32 "C:\Program Files\1cv8\8.3.24.1234\bin\comcntr.dll"

Номер релиза в пути подставьте свой — тот, что реально установлен в каталоге bin. Разрядность COM-коннектора должна совпадать с разрядностью клиента, который его вызывает. Если 1С запущена как 32-разрядное приложение, регистрируйте 32-разрядную comcntr.dll; для 64-разрядного процесса — 64-разрядную.

Отличие V83.COMConnector от V83.Application: коннектор создаёт лёгкое внешнее соединение без пользовательского интерфейса, в отдельном процессе. V83.Application поднимает полноценный сеанс с формами — он тяжелее и нужен редко, в основном когда без интерфейсных механизмов не обойтись.

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

Настройка COM-соединения с нуля
Выполнено: 0 / 6
Диагностика: выберите симптом

Передача параметров и совместимость типов данных

Внутри одной конфигурации параметры передаются как есть — компилятор знает все типы. Через COM-границу всё сложнее: данные проходят маршалинг между двумя процессами, и не каждый тип переживает эту дорогу.

Что передаётся через COM без хлопот:

  • ✅ Примитивы — Число, Строка, Дата, Булево, Неопределено. Проходят напрямую в обе стороны.
  • ✅ Простые значения в параметрах — их можно и передавать в вызываемую процедуру, и получать как результат функции.

Что требует отдельной обработки:

  • ⚠️ Ссылки и объекты (СправочникСсылка, ДокументОбъект) принадлежат той базе, где созданы. Через соединение вы получаете COM-обёртку, и каждое обращение к её свойству — это отдельный межпроцессный вызов.
  • ⚠️ Коллекции — ТаблицаЗначений, Массив, Структура, созданные в вызывающей базе, нельзя просто передать параметром в чужую базу.

Для сложных структур применяют сериализацию: на одной стороне объект пишется в строку через XDTO-сериализатор, на другой — читается обратно.

// В базе-источнике: таблицу в строку
ТекстXML = СериализаторXDTO.ЗаписатьXML(МояТаблица);
// Передаём ТекстXML как обычную строку в экспортную процедуру другой базы

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

Отдельно про Дата и пустые значения. Дата передаётся вместе с временем, поэтому если на приёмной стороне ждут дату без времени, время стоит отрезать явно (началом дня). Пустая ссылка и Неопределено — это разные вещи: сравнивать приходящее значение надёжнее через ЗначениеЗаполнено(), а не с конкретной константой, которой в чужой базе может и не оказаться.

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

Если вызываете не процедуру, а функцию, результат забирают обычным присваиванием:

Итог = Соединение.РаботаСОстатками.ПолучитьОстаток(Номенклатура, Склад);

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

Обработка ошибок и отладка вызовов

Любой вызов, который зависит от внешнего файла или другой базы, оборачивают в Попытка. Иначе одна недоступная база роняет всю операцию без внятного сообщения.

Попытка
    Коннектор = Новый COMОбъект("V83.COMConnector");
    Соединение = Коннектор.Connect(СтрокаПодключения);
    Соединение.РаботаСОстатками.ПересчитатьОстатки(Склад, Дата);
Исключение
    Текст = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
    ЗаписьЖурналаРегистрации("Обмен.COM", УровеньЖурналаРегистрации.Ошибка, , , Текст);
КонецПопытки;

ИнформацияОбОшибке() возвращает структуру с описанием, а ПодробноеПредставлениеОшибки разворачивает её в читаемый текст со стеком. Писать в журнал регистрации полезнее, чем показывать сообщение: фоновый обмен некому читать на экране.

Про отладку. Чтобы войти отладчиком в код, который исполняется по внешнему соединению, в целевой базе должна быть разрешена отладка. В клиент-серверном варианте это настраивается на уровне кластера (разрешение отладки по протоколу), в файловом — в Конфигураторе, в параметрах отладки.

Дальше в Конфигураторе целевой базы через Отладка → Подключение отладчик присоединяется к работающему предмету отладки. Внешнее соединение — это отдельный предмет, он появляется в списке, когда соединение активно. Точку останова ставят в экспортной процедуре заранее, до вызова из внешней программы.

Если точка останова не срабатывает, в 90% случаев дело в том, что отладка в целевой базе не включена или отладчик подключён не к тому процессу. Код при этом работает — просто молча, без остановки.

Производительность: когда COM, а когда веб-сервисы

COM-соединение удобно, но медленно на большом числе мелких обращений. Каждое чтение свойства чужого объекта — отдельный вызов между процессами с накладными расходами на маршалинг. Цикл на тысячу ссылок с десятком обращений к свойствам внутри превращается в десятки тысяч межпроцессных вызовов.

Что ускоряет интеграцию через COM:

  1. Держите соединение открытым. Не вызывайте Connect в цикле на каждую запись — подключайтесь один раз и переиспользуйте соединение.
  2. Передавайте данные пачками. Вместо тысячи вызовов по одной записи соберите данные в сериализованную строку и передайте одной экспортной процедурой.
  3. Переносите логику на сторону целевой базы. Пусть экспортная процедура сама делает запрос и возвращает готовый результат, а не отдаёт сырые ссылки на перебор.
  4. Минимизируйте обращения к свойствам обёрток. Каждое Соединение.Справочники.Номенклатура.НайтиПо... — это удалённый вызов.

Для регулярного обмена между базами COM всё чаще уступает веб-сервисам (SOAP) и HTTP-сервисам: они не требуют регистрации dll, работают по сети между серверами и переживают разную разрядность и расположение баз. COM хорош там, где обе базы на одной машине и нужен разовый или административный вызов.

Какой способ вызова выбрать?

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

Чем экспортная процедура отличается от обычной?
Только областью видимости. Обычная процедура доступна внутри своего модуля, экспортная (с ключевым словом Экспорт) — ещё и снаружи: из других модулей, из внешней обработки, через соединение.
Почему вызов падает с ошибкой «Метод объекта не обнаружен»?
Три причины: у процедуры нет ключевого слова Экспорт, имя в вызове написано с опечаткой, или у общего модуля не выставлен нужный флаг контекста (Сервер, Вызов сервера).
Нужно ли регистрировать comcntr.dll на каждой машине?
Да, на той машине, где исполняется код, создающий V83.COMConnector. И разрядность dll должна совпадать с разрядностью процесса 1С, который её вызывает.
Можно ли передать таблицу значений в процедуру другой базы?
Напрямую — нет. Таблицу сериализуют в строку XDTO-сериализатором в базе-источнике, передают как строковый параметр, а в целевой базе восстанавливают обратно.
Что быстрее для обмена — COM или веб-сервисы?
Для частого сетевого обмена с большим объёмом данных веб- и HTTP-сервисы обычно надёжнее и не привязаны к разрядности и расположению баз. COM выигрывает на разовых и локальных задачах, когда базы на одной машине.