Вызов процедур и функций во встроенном языке 1С:Предприятия 8.3 — от обычной строки кода до внешней обработки

· 10 мин

Содержание

Чтобы вызвать процедуру в 1С, напишите её имя и параметры в скобках: ЗаполнитьТаблицу(Контрагент, Дата);. Если процедура лежит в другом модуле, к имени добавляется владелец: РаботаСФайлами.Загрузить(Путь) для общего модуля или Обработка.Выполнить() для объекта. Вызвать её снаружи можно только тогда, когда в объявлении стоит слово Экспорт.

Дальше всё упирается в контекст. Код формы выполняется и на клиенте, и на сервере, внешняя обработка сначала подключается к базе, а имя метода может быть известно только во время работы программы. Ниже разобраны все эти случаи с рабочими примерами для платформы 8.3 и управляемых форм.

Синтаксис вызова: процедура, функция и параметры

Процедура выполняет действие и ничего не возвращает. Функция возвращает значение через Возврат. Отсюда первое правило вызова.

Процедура ЗаписатьВЖурнал(Текст, Уровень = "Информация")
    // ...
КонецПроцедуры

Функция СуммаСНДС(Сумма, Ставка = 20)
    Возврат Сумма + Сумма * Ставка / 100;
КонецФункции

// Вызов процедуры — отдельным оператором
ЗаписатьВЖурнал("Загрузка завершена");

// Вызов функции — в выражении
Итого = СуммаСНДС(1000);        // 1200
Итого = СуммаСНДС(1000, 10);    // 1100

// Функцию можно вызвать как процедуру, результат пропадёт
СуммаСНДС(1000);

Обратное не работает : строка Х = ЗаписатьВЖурнал("...") даст ошибку компиляции Использование процедуры как функции.

Как передаются параметры

  • 🔗 По ссылке — по умолчанию. Если процедура изменит параметр, изменится и переменная вызывающего кода.
  • 📦 По значению — с ключевым словом Знач. Процедура получает копию, исходная переменная не меняется.
  • ⚙️ Необязательные параметры — со значением по умолчанию: Уровень = "Информация".
  • ⏭️ Пропуск параметра — пустое место между запятыми: Отчет(Начало, , Истина). Подставится значение по умолчанию.
Процедура Удвоить(Число)
    Число = Число * 2;
КонецПроцедуры

Процедура УдвоитьКопию(Знач Число)
    Число = Число * 2;
КонецПроцедуры

А = 5;
Удвоить(А);       // А = 10
УдвоитьКопию(А);  // А по-прежнему 10

С Знач и коллекциями есть тонкость. Для таблицы значений или массива копируется только ссылка на объект. Если процедура добавит строку в таблицу, вызывающий код это увидит. Знач защищает лишь от присваивания параметру нового объекта.

Где искать процедуру и как к ней обратиться

Где объявленаНужен ли ЭкспортКак вызвать
Тот же модульНетИмяПроцедуры()
Общий модульДаИмяМодуля.ИмяПроцедуры()
Модуль объекта (документ, справочник)ДаДокументОбъект.ИмяПроцедуры()
Модуль менеджераДаДокументы.Реализация.ИмяПроцедуры()
Модуль формыДа, если зовут из другой формыФорма.ИмяПроцедуры() на клиенте
Глобальный общий модульДаИмяПроцедуры() без префикса

Процедура, объявленная ниже места вызова в том же модуле, вызывается без проблем: модуль компилируется целиком. Опережающее описание, как в старых языках, не нужно.

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

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

Сначала в модуле объекта обработки объявите метод:

// Модуль объекта внешней обработки
Функция ПересчитатьЦены(Документ, Процент) Экспорт
    // ...
    Возврат Истина;
КонецФункции

Подключение в управляемом приложении

В клиент-серверном варианте файл лежит у пользователя, а код обработки работает на сервере. Поэтому файл сначала передают во временное хранилище, а на сервере подключают по адресу.

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

&НаКлиенте
Процедура ПослеПомещенияФайла(Результат, Адрес, ИмяФайла, ДопПараметры) Экспорт
    Если Не Результат Тогда
        Возврат;
    КонецЕсли;
    ВыполнитьНаСервере(Адрес);
КонецПроцедуры

&НаСервере
Процедура ВыполнитьНаСервере(Адрес)
    ИмяОбработки = ВнешниеОбработки.Подключить(Адрес, , Ложь);
    Обработка = ВнешниеОбработки.Создать(ИмяОбработки);
    Успех = Обработка.ПересчитатьЦены(Объект.Ссылка, 5);
КонецПроцедуры

Третий параметр Подключить — безопасный режим. Ложь снимает ограничения: обработка получит доступ к файлам, COM и внешним компонентам. Такое разрешено только пользователю с административными правами, и делать это стоит лишь для проверенного кода.

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

Подключение по пути на сервере

Если файл уже лежит на сервере 1С, достаточно одной строки:

Обработка = ВнешниеОбработки.Создать("D:\Обработки\Пересчет.epf", Ложь);
Обработка.ПересчитатьЦены(ДокументСсылка, 5);

Путь здесь — путь на машине, где работает рабочий процесс сервера, а не на компьютере пользователя. Это самая частая причина ошибки «файл не найден» в клиент-серверной базе.

Вызов процедуры формы обработки

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

&НаКлиенте
Процедура ОткрытьИВызвать(ИмяОбработки)
    Форма = ПолучитьФорму("ВнешняяОбработка." + ИмяОбработки + ".Форма.Форма");
    Форма.Открыть();
    Форма.ЗаполнитьПоУмолчанию();   // метод формы с Экспорт
КонецПроцедуры

Имя ИмяОбработки — это строка, которую вернула ВнешниеОбработки.Подключить.

Дополнительные обработки через БСП

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

Вызов процедур в расширении конфигурации

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

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

  • ⬆️ &Перед("ИмяПроцедуры") — ваш код выполнится до типового.
  • ⬇️ &После("ИмяПроцедуры") — после типового.
  • 🔁 &Вместо("ИмяПроцедуры") — вместо типового. Исходный код вызывается через ПродолжитьВызов().
  • ✏️ &ИзменениеИКонтроль("ИмяПроцедуры") — правка текста процедуры с контролем изменений при обновлении.
&Вместо("ПриЗаписи")
Процедура Расш_ПриЗаписи(Отказ)
    Если ДополнительныеСвойства.Свойство("БезПроверок") Тогда
        Возврат;
    КонецЕсли;
    ПродолжитьВызов(Отказ);
КонецПроцедуры

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

Клиент и сервер: какую процедуру откуда можно вызвать

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

ДирективаГде работаетДоступ к данным формыКто может вызвать
&НаКлиентеКлиентДаТолько клиентский код
&НаСервереСерверДа, форма передаётся на серверКлиент и сервер
&НаСервереБезКонтекстаСерверНетКлиент и сервер
&НаКлиентеНаСервереБезКонтекстаТам, откуда вызвалиНетКлиент и сервер

Главное ограничение: серверная процедура не может вызвать клиентскую. Если после серверной работы нужно что-то показать пользователю, верните результат на клиент и уже там вызовите клиентскую процедуру.

Общие модули: флажки вместо директив

У общего модуля контекст задают флажки в свойствах:

  • 🖥️ Клиент (управляемое приложение) — модуль доступен клиентскому коду.
  • 🗄️ Сервер — модуль компилируется на сервере.
  • 📞 Вызов сервера — серверные экспортные методы можно вызывать с клиента. Без этого флажка клиентский код такой модуль не видит.
  • 🔌 Внешнее соединение — доступ через COM-соединение.
  • 🔒 Привилегированный — код выполняется без проверки прав.

Типовая схема: клиентская процедура формы вызывает ВыгрузкаВызовСервера.Сформировать(Параметры). Модуль с флажком «Вызов сервера» только принимает вызов. Работу он передаёт серверному модулю без этого флажка.

Асинхронные вызовы на клиенте

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

&НаКлиенте
Процедура Удалить(Команда)
    Оповещение = Новый ОписаниеОповещения("ПослеВопроса", ЭтотОбъект);
    ПоказатьВопрос(Оповещение, "Удалить строки?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры

&НаКлиенте
Процедура ПослеВопроса(Ответ, ДопПараметры) Экспорт
    Если Ответ = КодВозвратаДиалога.Да Тогда
        УдалитьНаСервере();
    КонецЕсли;
КонецПроцедуры

С платформы 8.3.18 вместо этого можно объявить функцию с Асинх и ждать результата через Ждать. Код получается линейным, без отдельной процедуры-продолжения.

Вызов по имени из строки и ВызватьИсключение

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

Оператор Выполнить и функция Вычислить

ИмяМетода = "ОбменДанными.ЗагрузитьПакет";
Выполнить(ИмяМетода + "(Параметр1, Параметр2)");

// Если нужен результат — Вычислить
Результат = Вычислить("Ценообразование.ЦенаНаДату(Номенклатура, Дата)");

Переменные Параметр1, Номенклатура, Дата должны существовать в том месте, где выполняется строка: она компилируется в текущем контексте.

Никогда не собирайте строку для Выполнить из данных, которые ввёл пользователь или прислала внешняя система. Это прямой путь к выполнению чужого кода. Перед вызовом включайте УстановитьБезопасныйРежим(Истина), если имя метода пришло извне.

В конфигурациях на БСП удобнее готовые методы. ОбщегоНазначения.ВыполнитьМетодКонфигурации(ИмяМетода, Параметры) принимает имя и массив параметров. Перед вызовом он проверяет, что имя похоже на имя метода, а не на произвольный код.

Вызов процедуры, которой может не быть

Типичная задача — вызвать метод из расширения, только если расширение установлено. Без проверки получите ошибку Метод объекта не обнаружен. Безопасный вариант — обернуть вызов в Попытка:

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

ВызватьИсключение: как процедура сообщает об ошибке

ВызватьИсключение прерывает процедуру и передаёт ошибку тому, кто её вызвал. Если вызывающий код не поймал исключение в Попытка, пользователь увидит окно с текстом, а транзакция откатится.

Процедура ПровестиОплату(Сумма) Экспорт
    Если Сумма <= 0 Тогда
        ВызватьИсключение "Сумма оплаты должна быть больше нуля";
    КонецЕсли;
    // ...
КонецПроцедуры

Внутри блока Исключение оператор без текста — просто ВызватьИсключение; — пробрасывает исходную ошибку выше с сохранением стека. Так делают, когда нужно записать ошибку в журнал, но не глушить её.

Отладка: почему процедура не вызывается или падает

Текст ошибки обычно прямо указывает на причину. Разберите свой случай по симптому.

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

Пошаговая отладка вызова

  1. Откройте модуль в Конфигураторе и поставьте точку останова на строке вызова — клавиша F9.
  2. Запустите отладку: Отладка → Начать отладку и выберите вариант клиента.
  3. Когда выполнение остановится, нажмите F11 («Шагнуть в»), чтобы войти внутрь вызываемой процедуры. F10 выполнит вызов целиком, не заходя внутрь, Shift+F11 вернёт из процедуры на уровень выше.
  4. Окно стека вызовов показывает цепочку: какая процедура кого вызвала. По нему видно, откуда пришли неожиданные параметры.
  5. Значения переменных смотрите в табло или через Shift+F9 на выделенном выражении.

Отладка внешней обработки. Откройте файл .epf в Конфигураторе через Файл → Открыть, поставьте точки останова в его модуле. Затем в пользовательском режиме, запущенном из Конфигуратора, откройте ту же обработку через Файл → Открыть. Отладчик остановится на ваших точках.

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

Как вызывать процедуры быстро и надёжно

Каждый вызов с клиента на сервер — сетевой обмен. На медленном канале одна лишняя серверная процедура в цикле превращает секундную операцию в минутную.

  • 🚀 Один серверный вызов вместо десяти. Соберите данные на клиенте в структуру и отправьте разом, а не вызывайте сервер для каждой строки табличной части.
  • 🪶 &НаСервереБезКонтекста там, где форма не нужна. Директива &НаСервере гонит на сервер и обратно все данные формы, включая таблицы на тысячи строк.
  • ♻️ Повторное использование возвращаемых значений. У общего модуля есть свойство «Повторное использование возвращаемых значений»: «На время вызова» или «На время сеанса». Функция с одинаковыми параметрами вычислится один раз, дальше результат берётся из кэша. Подходит для настроек и констант, но не для данных, которые меняются в течение сеанса.
  • 📏 Короткие процедуры с понятным именем. Глагол в начале (Заполнить, Проверить, Получить), одна задача на процедуру. Такую процедуру легче вызвать повторно и отладить.
  • 🧩 Структура вместо десяти параметров. Когда параметров больше пяти, передавайте Структура. Добавление нового поля не сломает старые вызовы.
  • 🛑 Динамический вызов — только по необходимости. Ошибки в Выполнить не ловит синтаксический контроль, их видно лишь при запуске. Прямой вызов надёжнее.

Для поиска медленных вызовов включите замер производительности (Отладка → Замер производительности). Он покажет, на какой строке и в какой процедуре уходит время.

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

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