Вызов процедур и функций во встроенном языке 1С:Предприятия 8.3 — от обычной строки кода до внешней обработки
Содержание
Чтобы вызвать процедуру в 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 Тогда
ВызватьИсключение "Сумма оплаты должна быть больше нуля";
КонецЕсли;
// ...
КонецПроцедуры
Внутри блока Исключение оператор без текста — просто ВызватьИсключение; — пробрасывает исходную ошибку выше с сохранением стека. Так делают, когда нужно записать ошибку в журнал, но не глушить её.
Отладка: почему процедура не вызывается или падает
Текст ошибки обычно прямо указывает на причину. Разберите свой случай по симптому.
Пошаговая отладка вызова
- Откройте модуль в Конфигураторе и поставьте точку останова на строке вызова — клавиша
F9. - Запустите отладку:
Отладка → Начать отладкуи выберите вариант клиента. - Когда выполнение остановится, нажмите
F11(«Шагнуть в»), чтобы войти внутрь вызываемой процедуры.F10выполнит вызов целиком, не заходя внутрь,Shift+F11вернёт из процедуры на уровень выше. - Окно стека вызовов показывает цепочку: какая процедура кого вызвала. По нему видно, откуда пришли неожиданные параметры.
- Значения переменных смотрите в табло или через
Shift+F9на выделенном выражении.
Отладка внешней обработки. Откройте файл .epf в Конфигураторе через Файл → Открыть, поставьте точки останова в его модуле. Затем в пользовательском режиме, запущенном из Конфигуратора, откройте ту же обработку через Файл → Открыть. Отладчик остановится на ваших точках.
Если точки останова на сервере не срабатывают в клиент-серверной базе, проверьте, что сервер 1С запущен с разрешённой отладкой (ключ -debug у службы агента). Перезапуск службы обрывает сеансы всех пользователей, поэтому включайте отладку на тестовом сервере или в нерабочее время.
Как вызывать процедуры быстро и надёжно
Каждый вызов с клиента на сервер — сетевой обмен. На медленном канале одна лишняя серверная процедура в цикле превращает секундную операцию в минутную.
- 🚀 Один серверный вызов вместо десяти. Соберите данные на клиенте в структуру и отправьте разом, а не вызывайте сервер для каждой строки табличной части.
- 🪶
&НаСервереБезКонтекстатам, где форма не нужна. Директива&НаСерверегонит на сервер и обратно все данные формы, включая таблицы на тысячи строк. - ♻️ Повторное использование возвращаемых значений. У общего модуля есть свойство «Повторное использование возвращаемых значений»: «На время вызова» или «На время сеанса». Функция с одинаковыми параметрами вычислится один раз, дальше результат берётся из кэша. Подходит для настроек и констант, но не для данных, которые меняются в течение сеанса.
- 📏 Короткие процедуры с понятным именем. Глагол в начале (
Заполнить,Проверить,Получить), одна задача на процедуру. Такую процедуру легче вызвать повторно и отладить. - 🧩 Структура вместо десяти параметров. Когда параметров больше пяти, передавайте
Структура. Добавление нового поля не сломает старые вызовы. - 🛑 Динамический вызов — только по необходимости. Ошибки в
Выполнитьне ловит синтаксический контроль, их видно лишь при запуске. Прямой вызов надёжнее.
Для поиска медленных вызовов включите замер производительности (Отладка → Замер производительности). Он покажет, на какой строке и в какой процедуре уходит время.
Частые вопросы
Можно ли вызвать процедуру из модуля формы документа в модуле объекта?
Как вызвать процедуру 1С из внешней программы?
V83.COMConnector) или HTTP-сервис. Из COM-соединения доступны экспортные методы общих модулей с флажком «Внешнее соединение».Чем Выполнить отличается от Вычислить?
Выполнить выполняет фрагмент кода и ничего не возвращает. Вычислить принимает одно выражение и возвращает его значение, поэтому подходит для вызова функции.Почему процедура обработки отрабатывает у администратора, но не у бухгалтера?
Можно ли передать в серверную процедуру объект документа?
Ссылка.ПолучитьОбъект(). Объект документа не передаётся между клиентом и сервером.