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

· 10 мин

Содержание

В 1С к процедуре обращаются по имени со скобками: ЗаполнитьТаблицу(Дата, Склад);. Если процедура лежит в том же модуле, хватает имени. Если в другом, её объявляют с ключевым словом Экспорт и вызывают через модуль: РаботаСЦенами.ЗаполнитьТаблицу(Дата, Склад); для общего модуля или Справочники.Номенклатура.ЗаполнитьТаблицу(...) для модуля менеджера.

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

Синтаксис вызова процедуры в модуле 1С

Процедура объявляется так:

Процедура ПересчитатьСумму(Количество, Цена, Сумма)
    Сумма = Количество * Цена;
КонецПроцедуры

Вызов — отдельный оператор с точкой с запятой:

Сумма = 0;
ПересчитатьСумму(5, 120, Сумма);
// Сумма = 600

Главное отличие процедуры от функции: процедура не возвращает значение. Её нельзя поставить в правую часть присваивания или в условие. Строка Итог = ПересчитатьСумму(5, 120, Сумма); не скомпилируется: модуль покажет ошибку Использование процедуры как функции.

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

Функция Наценка(Цена, Процент)
    Возврат Цена * (1 + Процент / 100);
КонецФункции

НоваяЦена = Наценка(1000, 25);  // 1250
Наценка(1000, 25);               // допустимо, результат отброшен

Несколько правил, о которых часто спрашивают новички:

  • 📌 Регистр букв в имени не важен: пересчитатьсумму() и ПересчитатьСумму() — один и тот же вызов.
  • 📌 Скобки обязательны даже без параметров: ОбновитьИтоги();.
  • 📌 В 8.3 процедуру можно вызвать выше по тексту, чем она объявлена: компилятор видит весь модуль целиком. Предварительное объявление через Далее было нужно в 1С 7.7, в восьмёрке без него обходятся.
  • 📌 Досрочно выйти из процедуры можно оператором Возврат; без значения.
Что вызываемГде объявленоКак обращаться
Процедура того же модуляэтот же модульИмяПроцедуры(...)
Процедура общего модуляобщий модуль, ЭкспортИмяМодуля.ИмяПроцедуры(...)
Метод модуля менеджерамодуль менеджера, ЭкспортДокументы.ПриходТовара.ИмяПроцедуры(...)
Метод модуля объектамодуль объекта, ЭкспортДокументОбъект.ИмяПроцедуры(...)
Метод формымодуль формы, Экспорт, &НаКлиентеФорма.ИмяПроцедуры(...)
Глобальный общий модульобщий модуль с флагом «Глобальный»ИмяПроцедуры(...) без имени модуля

Как передавать параметры в процедуру

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

Чтобы процедура не трогала исходную переменную, перед параметром ставят Знач:

Процедура Округлить(Знач Число, Результат)
    Число = Окр(Число, 2);   // меняется только локальная копия
    Результат = Число;
КонецПроцедуры

С объектами есть тонкость. Таблица значений, структура или массив, переданные даже через Знач, меняются внутри процедуры: копируется ссылка на объект, а не сам объект. Знач защищает только от замены переменной целиком, например от Таблица = Новый ТаблицаЗначений.

Необязательные параметры и значения по умолчанию

Параметру можно задать значение по умолчанию. Тогда при вызове его разрешено пропустить:

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

ЗаписатьВЖурнал("Загрузка завершена");
ЗаписатьВЖурнал("Нет связи", "Ошибка");
ЗаписатьВЖурнал("Нет связи", , Истина);   // второй пропущен запятой

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

Когда параметров много

Если параметров больше пяти-шести, их удобнее собрать в структуру и передать одним аргументом. Так поступают в типовых конфигурациях на БСП:

Параметры = Новый Структура;
Параметры.Вставить("Организация", Организация);
Параметры.Вставить("Период", ТекущаяДатаСеанса());
Параметры.Вставить("ТолькоПроведенные", Истина);

СформироватьДвижения(Параметры);

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

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

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

Процедура ПровестиПоРегистрам(Отказ) Экспорт
    ПроверитьОстатки(Отказ);   // неэкспортная, вызывается только отсюда
КонецПроцедуры

Где что видно:

  • 🔹 Модуль формы — процедуры доступны только этой форме. Снаружи можно вызвать экспортную клиентскую процедуру, если есть ссылка на открытую форму.
  • 🔹 Модуль объекта — экспортные методы вызываются у экземпляра: Объект = Ссылка.ПолучитьОбъект(); Объект.ЗаполнитьПоОснованию(...).
  • 🔹 Модуль менеджера — экспортные методы вызываются без экземпляра, через менеджер: Справочники.Контрагенты.НайтиПоИНН(ИНН).
  • 🔹 Общий модуль — экспортные методы доступны всей конфигурации с учётом флагов контекста (о них ниже).
  • 🔹 Модуль приложения и модуль сеанса — используются для обработчиков событий запуска, а не как библиотека.

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

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

Клиент и сервер: как обратиться к процедуре из другого контекста

В управляемом приложении код выполняется либо на клиенте, либо на сервере. Контекст в модуле формы задают директивы компиляции перед процедурой:

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

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

&НаКлиенте
Процедура Заполнить(Команда)
    ЗаполнитьНаСервере();
КонецПроцедуры

&НаСервере
Процедура ЗаполнитьНаСервере()
    Объект.Товары.Очистить();
    // запрос к базе и заполнение табличной части
КонецПроцедуры

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

Почему стоит выбирать «БезКонтекста»

Вызов &НаСервере передаёт на сервер всю форму с реквизитами и табличными частями, а потом возвращает её обратно. На форме с тысячей строк это заметно тормозит. Если процедуре нужны только два значения, используйте &НаСервереБезКонтекста и передайте их параметрами:

&НаСервереБезКонтекста
Функция ОстатокТовара(Номенклатура, Склад)
    Запрос = Новый Запрос(
    "ВЫБРАТЬ ЕСТЬNULL(СУММА(Т.КоличествоОстаток), 0) КАК Остаток
    |ИЗ РегистрНакопления.ТоварыНаСкладах.Остатки(, Номенклатура = &Н И Склад = &С) КАК Т");
    Запрос.УстановитьПараметр("Н", Номенклатура);
    Запрос.УстановитьПараметр("С", Склад);
    Возврат Запрос.Выполнить().Выгрузить()[0].Остаток;
КонецФункции

Имя регистра в примере условное, подставьте своё.

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

Флаги общих модулей

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

  • ✅ Модуль с флагом «Сервер» без «Вызов сервера» виден только из серверного кода. С клиента его процедуру не вызвать.
  • ✅ Чтобы клиент мог обратиться к серверной процедуре общего модуля, нужен флаг «Вызов сервера». Типовые конфигурации называют такие модули с суффиксом ВызовСервера.
  • ✅ Модуль с флагом «Клиент» нужен для процедур, которые работают с интерфейсом: открывают формы, показывают вопросы.

Динамический вызов и асинхронные процедуры

Иногда имя процедуры приходит из настройки или строки. Тогда вызывают через Выполнить():

ИмяМетода = "ОбменДанными.ВыгрузитьКонтрагентов";
Выполнить(ИмяМетода + "()");

Для функции используют Вычислить(), он возвращает значение:

Результат = Вычислить("РаботаСЦенами.ТекущаяЦена(Номенклатура)");

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

Обращение к процедуре-обработчику через ОписаниеОповещения

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

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

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

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

Чем отличается вызов в разных версиях платформы

Синтаксис самого вызова со времён 8.0 почти не менялся. Менялось окружение вокруг него.

ВерсияЧто изменилось для вызова процедур
1С 7.7процедуру, вызванную выше объявления, требовалось объявить заранее через Далее
8.0–8.1, обычные формывесь код формы на клиенте, директив компиляции нет
8.2, управляемые формыпоявились директивы &НаКлиенте, &НаСервере, флаги общих модулей, вызов сервера
8.3, режим без модальностимодальные вызовы заменяют на ОписаниеОповещения и экспортные обработчики
8.3.18 и новееасинхронные процедуры и функции: ключевые слова Асинх и Ждать

Асинхронный вариант делает код линейным, без отдельной процедуры-обработчика:

&НаКлиенте
Асинх Процедура Удалить(Команда)
    Ответ = Ждать ВопросАсинх("Удалить строку?", РежимДиалогаВопрос.ДаНет);
    Если Ответ = КодВозвратаДиалога.Да Тогда
        // удаление
    КонецЕсли;
КонецПроцедуры

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

В конфигурациях на обычных формах (старые УПП, Комплексная 1.1) директивы клиента и сервера в модулях форм не используются. Там процедура формы вызывает процедуру модуля объекта напрямую.

Отладка вызова процедуры в Конфигураторе

Чтобы увидеть, доходит ли выполнение до процедуры и с какими параметрами:

  1. Откройте модуль, установите курсор на первую строку процедуры и нажмите F9 — появится точка останова.
  2. Запустите отладку: Отладка → Начать отладку или F5.
  3. Выполните в режиме 1С:Предприятие действие, которое вызывает процедуру.
  4. Когда выполнение остановится, наведите курсор на параметр — подсказка покажет значение. Для таблиц и структур удобнее табло или окно «Вычислить выражение» (Shift+F9).
  5. Шагайте: F11 — зайти внутрь вызываемой процедуры, F10 — выполнить строку без захода, Shift+F11 — выйти из текущей процедуры.
  6. Окно «Стек вызовов» (Ctrl+Alt+C) показывает цепочку: какая процедура вызвала текущую и из какого модуля.

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

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

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

Ошибки при обращении к процедуре и как их исправить

Сообщения платформы короткие, но по ним точно понятно, что не так. Выберите свой текст:

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

После переименования процедуры найдите все места вызова через Правка → Глобальный поиск (Ctrl+Shift+F) по старому имени. Синтаксический контроль модуля проверяет только сам модуль, поэтому для всей конфигурации запустите Конфигурация → Проверка конфигурации.

Можно ли вызвать процедуру модуля формы из общего модуля?
Только экспортную клиентскую процедуру и только через ссылку на открытую форму, например переданную параметром. Серверные процедуры формы снаружи не вызываются.
Как вызвать процедуру внешней обработки?
Подключите обработку, получите объект через ВнешниеОбработки.Создать(...) и вызовите экспортную процедуру её модуля объекта: например Обработка.ЗагрузитьДанные().
Можно ли передать процедуру как параметр в другую процедуру?
Напрямую — нет. Передают имя строкой для Выполнить() или объект ОписаниеОповещения, который потом запускают через ВыполнитьОбработкуОповещения.
Влияет ли количество вызовов сервера на скорость?
Да. Каждый вызов с клиента на сервер — сетевой обмен. Собирайте серверную работу в один вызов, а не дёргайте сервер в цикле по строкам.
Почему процедура вызывается, но изменения параметра не видны снаружи?
Скорее всего, параметр объявлен с Знач. Уберите его или верните значение из функции.