При разработке расширений в системе 1С:Предприятие 8.3 программисты часто сталкиваются с ситуацией, когда вполне корректный код в модуле менеджера внезапно перестает работать после добавления его в расширение. Типичный сценарий: вы перехватываете функцию через аннотацию &Вместо, и при запуске приложения или выполнении операции система выдает ошибку: «Переменная не определена (ИмяОбщегоМодуля)». При этом в основной конфигурации этот же код работает без нареканий.
В данной статье мы подробно проанализируем, почему возникает эта ошибка, разберем механизмы компиляции расширений и рассмотрим проверенные способы решения проблемы, включая использование инструкций препроцессора и специальных «процедур-пустышек» (также рекомендуем Анализ конфигураций и расширений на наличие ошибок).
Давайте проанализируем ситуацию. Модуль менеджера документа или справочника в 1С является универсальным — его код может исполняться как на сервере, так и на клиенте (например, в толстом клиенте). Однако общие модули, к которым обращается менеджер (например, ПроведениеСерверУТ), зачастую имеют флаг «Сервер» и не имеют флага «Клиент».
Когда мы создаем расширение и добавляем в него метод модуля менеджера, платформа 1С выполняет процедуру объединения (слияния) исходного кода и кода расширения. В этот момент происходит перекомпиляция модуля для всех возможных контекстов. Если код в расширении не ограничен инструкциями препроцессора, платформа пытается скомпилировать вызов серверного общего модуля в контексте клиента. Поскольку в клиентском контексте серверный модуль «не виден», компилятор выдает ошибку: «Переменная не определена».
Первым и самым правильным шагом будет ограничение области видимости кода в расширении. Мы должны гарантировать, что вызовы серверных модулей будут происходить только там, где они доступны. Рассмотрим, как правильно оформить модуль менеджера в расширении. Нам необходимо обернуть весь замещающий код в блок #Если.
Проанализируем пример реализации (похожий прием используется для задачи Отключение вызова обработки Результаты обновления программы для УТ):
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
&Вместо("ОбработкаПроведения")
Процедура Расш1_ОбработкаПроведения(Отказ, РежимПроведения)
// Здесь мы вызываем серверный модуль, который вызывал оригинальный метод
ПроведениеСерверУТ.ВыполнитьПроведение(ЭтотОбъект, Отказ);
КонецПроцедуры
#КонецЕсли
Использование такой конструкции «подсказывает» платформе, что данный фрагмент кода не нужно пытаться компилировать для тонкого клиента, где серверные модули недоступны. Это решает основную проблему с видимостью переменных.
Иногда после применения первого решения разработчики сталкиваются с новой ошибкой: «Ожидается определение процедуры или функции». Выясним причину: если мы обернули весь код модуля расширения в инструкции препроцессора, то для контекста Тонкого клиента модуль оказывается абсолютно пустым. В некоторых версиях платформы (например, 8.3.20, 8.3.21) пустой модуль расширения считается ошибкой компиляции.
Чтобы обойти это ограничение, мы можем использовать «процедуру-пустышку», которая будет находиться вне блоков препроцессора или в блоке #Иначе. Это гарантирует, что компилятор всегда найдет в модуле хотя бы одно определение метода.
Разберем пример кода с использованием блока #Иначе:
#Если Сервер Или ТолстыйКлиентОбычноеПриложение Или ВнешнееСоединение Тогда
&Вместо("ТиповаяФункция")
Функция Расш1_ТиповаяФункция()
// Ваш рабочий код, использующий серверные модули
Возврат ПродолжитьВызов();
КонецФункции
#Иначе
// Эта часть скомпилируется в тонком клиенте
Процедура Служебная_ДляКомпиляцииМодуля()
// Процедура ничего не делает, но предотвращает ошибку пустого модуля
КонецПроцедуры
#КонецЕсли
Этот прием позволяет успешно запустить приложение в любом режиме, не нарушая логику работы расширения.
Если вышеописанные методы не помогают, стоит обратить внимание на настройки самого расширения и заимствованных объектов. Рассмотрим важные моменты:
Если вы используете директиву &ИзменениеИКонтроль, помните, что механизм замены строк крайне чувствителен к контексту. Посмотрим на основные правила:
Во-первых, не удаляйте комментарии и лишние строки внутри блоков #Вставка и #Удаление без необходимости, так как это может нарушить сопоставление кода платформой. Во-вторых, если оригинальный код функции в модуле менеджера уже обернут в инструкции препроцессора (что часто встречается в типовых конфигурациях вроде УТ 11 или ERP), то в расширении ваша аннотация обязательно должна находиться внутри точно такого же блока #Если....
Проанализируем итоговый чек-лист для исправления ошибки:
#Если Сервер....Соблюдение этих правил позволит вам создавать стабильные расширения, которые корректно работают во всех режимах запуска системы 1С.