Как обратиться к экспортной процедуре 1С из кода и внешней обработки
Содержание
Чтобы вызвать процедуру из другого модуля, её объявляют с ключевым словом Экспорт. Без него метод виден только внутри своего модуля. Дальше обращение зависит от того, где процедура лежит: в общем модуле её вызывают через ИмяМодуля.ИмяПроцедуры(...), в файле .epf — через менеджер ВнешниеОбработки, а в другой информационной базе — через COM-соединение V83.COMConnector.
Разберём все три сценария: от простого обращения внутри конфигурации до вызова экспортной процедуры в чужой базе по COM. С синтаксисом, передачей параметров и типичными ошибками, на которые уходит больше всего времени.
Что делает ключевое слово «Экспорт» и откуда видна процедура
Экспорт ставится в заголовке процедуры или функции и открывает её для вызова извне модуля:
Процедура ПересчитатьОстатки(Склад, ДатаРасчёта) Экспорт
// тело процедуры
КонецПроцедуры
Где объявлена процедура — оттуда и зависит способ обращения:
- 📦 Общий модуль. Вызов по имени модуля:
РаботаСОстатками.ПересчитатьОстатки(Склад, Дата). Это основной способ переиспользовать код внутри конфигурации. - 🧾 Модуль объекта (документа, обработки, справочника). Экспортный метод доступен через ссылку на объект:
ДокументОбъект.Провести()— после того как объект получен. - 🗂 Модуль формы. Экспортные методы формы видны тем, кто получил эту форму программно.
У общего модуля важны флаги в его свойствах: Клиент (управляемое приложение), Сервер, Вызов сервера. Если процедура должна работать на сервере, а флаг Сервер снят — вызов просто не скомпилируется. Это первое, что стоит проверить, когда «процедура не находится».
Для вызова внутри конфигурации ничего регистрировать не нужно — компилятор видит все модули. Сложности начинаются, когда код лежит во внешнем файле или в другой базе.
Вызов экспортной процедуры из внешней обработки
Внешняя обработка (файл .epf) подключается во время работы и несёт собственный модуль объекта. Экспортные процедуры этого модуля вызывают так:
Обработка = ВнешниеОбработки.Создать("C:\Обмен\Пересчёт.epf");
Обработка.ПересчитатьОстатки("Основной склад", ТекущаяДата());
ВнешниеОбработки — глобальное свойство контекста, оно возвращает менеджер внешних обработок. Метод Создать принимает путь к файлу и возвращает объект, у которого доступны все экспортные методы его модуля объекта.
Разберём параметры Создать по порядку:
- Путь к файлу
.epf— абсолютный путь на том компьютере, где исполняется код (на клиенте или на сервере — в зависимости от контекста). - Безопасный режим — второй параметр. Значение
Истиназапускает обработку с ограничениями: без доступа к файловой системе, COM и внешним компонентам. Для доверенного кода ставятЛожь. - Уникальный ключ — третий параметр, нужен, если одну обработку подключают несколько раз и важно различать экземпляры.
Для внешнего отчёта (.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-границу всё сложнее: данные проходят маршалинг между двумя процессами, и не каждый тип переживает эту дорогу.
Что передаётся через COM без хлопот:
- ✅ Примитивы —
Число,Строка,Дата,Булево,Неопределено. Проходят напрямую в обе стороны. - ✅ Простые значения в параметрах — их можно и передавать в вызываемую процедуру, и получать как результат функции.
Что требует отдельной обработки:
- ⚠️ Ссылки и объекты (
СправочникСсылка,ДокументОбъект) принадлежат той базе, где созданы. Через соединение вы получаете COM-обёртку, и каждое обращение к её свойству — это отдельный межпроцессный вызов. - ⚠️ Коллекции —
ТаблицаЗначений,Массив,Структура, созданные в вызывающей базе, нельзя просто передать параметром в чужую базу.
Для сложных структур применяют сериализацию: на одной стороне объект пишется в строку через XDTO-сериализатор, на другой — читается обратно.
// В базе-источнике: таблицу в строку
ТекстXML = СериализаторXDTO.ЗаписатьXML(МояТаблица);
// Передаём ТекстXML как обычную строку в экспортную процедуру другой базы
На принимающей стороне экспортная процедура получает строку и восстанавливает объект своим сериализатором. Так через COM-границу проходят любые данные — ценой того, что их нужно явно упаковать и распаковать.
Отдельно про Дата и пустые значения. Дата передаётся вместе с временем, поэтому если на приёмной стороне ждут дату без времени, время стоит отрезать явно (началом дня). Пустая ссылка и Неопределено — это разные вещи: сравнивать приходящее значение надёжнее через ЗначениеЗаполнено(), а не с конкретной константой, которой в чужой базе может и не оказаться.
Выходные параметры (переданные по ссылке, то есть не через Знач) при вызове по COM работают не всегда предсказуемо. Надёжнее возвращать результат функцией или собирать его в строку, чем рассчитывать на изменение параметра внутри чужой базы.
Если вызываете не процедуру, а функцию, результат забирают обычным присваиванием:
Итог = Соединение.РаботаСОстатками.ПолучитьОстаток(Номенклатура, Склад);
При этом возвращать из такой функции лучше примитив или сериализованную строку. Если функция вернёт ссылку или таблицу значений чужой базы, вы снова получите COM-обёртку с дорогим перебором на вашей стороне.
Обработка ошибок и отладка вызовов
Любой вызов, который зависит от внешнего файла или другой базы, оборачивают в Попытка. Иначе одна недоступная база роняет всю операцию без внятного сообщения.
Попытка
Коннектор = Новый COMОбъект("V83.COMConnector");
Соединение = Коннектор.Connect(СтрокаПодключения);
Соединение.РаботаСОстатками.ПересчитатьОстатки(Склад, Дата);
Исключение
Текст = ПодробноеПредставлениеОшибки(ИнформацияОбОшибке());
ЗаписьЖурналаРегистрации("Обмен.COM", УровеньЖурналаРегистрации.Ошибка, , , Текст);
КонецПопытки;
ИнформацияОбОшибке() возвращает структуру с описанием, а ПодробноеПредставлениеОшибки разворачивает её в читаемый текст со стеком. Писать в журнал регистрации полезнее, чем показывать сообщение: фоновый обмен некому читать на экране.
Про отладку. Чтобы войти отладчиком в код, который исполняется по внешнему соединению, в целевой базе должна быть разрешена отладка. В клиент-серверном варианте это настраивается на уровне кластера (разрешение отладки по протоколу), в файловом — в Конфигураторе, в параметрах отладки.
Дальше в Конфигураторе целевой базы через Отладка → Подключение отладчик присоединяется к работающему предмету отладки. Внешнее соединение — это отдельный предмет, он появляется в списке, когда соединение активно. Точку останова ставят в экспортной процедуре заранее, до вызова из внешней программы.
Если точка останова не срабатывает, в 90% случаев дело в том, что отладка в целевой базе не включена или отладчик подключён не к тому процессу. Код при этом работает — просто молча, без остановки.
Производительность: когда COM, а когда веб-сервисы
COM-соединение удобно, но медленно на большом числе мелких обращений. Каждое чтение свойства чужого объекта — отдельный вызов между процессами с накладными расходами на маршалинг. Цикл на тысячу ссылок с десятком обращений к свойствам внутри превращается в десятки тысяч межпроцессных вызовов.
Что ускоряет интеграцию через COM:
- Держите соединение открытым. Не вызывайте
Connectв цикле на каждую запись — подключайтесь один раз и переиспользуйте соединение. - Передавайте данные пачками. Вместо тысячи вызовов по одной записи соберите данные в сериализованную строку и передайте одной экспортной процедурой.
- Переносите логику на сторону целевой базы. Пусть экспортная процедура сама делает запрос и возвращает готовый результат, а не отдаёт сырые ссылки на перебор.
- Минимизируйте обращения к свойствам обёрток. Каждое
Соединение.Справочники.Номенклатура.НайтиПо...— это удалённый вызов.
Для регулярного обмена между базами COM всё чаще уступает веб-сервисам (SOAP) и HTTP-сервисам: они не требуют регистрации dll, работают по сети между серверами и переживают разную разрядность и расположение баз. COM хорош там, где обе базы на одной машине и нужен разовый или административный вызов.
Частые вопросы
Чем экспортная процедура отличается от обычной?
Экспорт) — ещё и снаружи: из других модулей, из внешней обработки, через соединение.Почему вызов падает с ошибкой «Метод объекта не обнаружен»?
Экспорт, имя в вызове написано с опечаткой, или у общего модуля не выставлен нужный флаг контекста (Сервер, Вызов сервера).Нужно ли регистрировать comcntr.dll на каждой машине?
V83.COMConnector. И разрядность dll должна совпадать с разрядностью процесса 1С, который её вызывает.