При разработке универсальных внешних отчетов и обработок в платформе 1С:Предприятие 7.7 разработчики часто сталкиваются с необходимостью вызова функций или процедур из глобального модуля (например, типовой функции глПредставлениеДокумента). Если такая обработка открывается в нетиповой или другой конфигурации, где процедура отсутствует, платформа аварийно прерывает работу с ошибкой компиляции модуля.
В этой статье разберем, почему возникает эта проблема, какие ограничения накладывает среда исполнения 1С 7.7 и какими способами можно безопасно проверить наличие метода или обойти его отсутствие.
Проанализируем архитектурные ограничения платформы 1С:Предприятие 7.7:
Попытка ... Исключение в теле модуля здесь не помогает, так как ошибка возникает на этапе компиляции, а не во время исполнения.Шаблон(): Попытка вызвать функцию динамически через выражение вида Шаблон("[глФункция()]") позволяет обойти ошибку компиляции основного модуля, однако при отсутствии функции платформа транслирует системную ошибку непосредственно в окно сообщений (табло), возвращая пустую строку или исходный текст, не вызывая исключительной ситуации для перехвата.Выполнить(): Во встроенном языке 1С 7.7 штатно нет прямого аналога динамического исполнения строкового кода, как в платформе 8.x.Рассмотрим наиболее простой и надежный штатный способ, не требующий генерации внешних файлов и внешних компонент. Если мы знаем, в каких именно типовых конфигурациях присутствует нужная глобальная процедура, мы можем идентифицировать конфигурацию по уникальным объектам метаданных с помощью метода Выбран().
Посмотрим на пример кода:
Если Метаданные.Регистр("ОстаткиТМЦ").Выбран() = 1 Тогда
// Это конфигурация Торговля и Склад, функция гарантированно есть
СтрокаКода = "[глПредставлениеДокумента(Докум.ДокОснование)]";
ДокументРасчета = Шаблон(СтрокаКода);
Иначе
// Альтернативное представление для прочих конфигураций
ДокументРасчета = Докум.ДокОснование.Вид() + " " + Докум.ДокОснование.НомерДок;
КонецЕсли;
Такой подход полностью исключает появление сообщений об ошибках в табло, так как динамический вызов через Шаблон() происходит только тогда, когда конфигурация гарантированно содержит нужный метод.
Если требуется точно узнать, существует ли конкретная процедура в глобальном модуле текущей информационной базы (не привязываясь к метаданным), разберем штатный способ с созданием временного файла обработки и проверкой его компиляции в блоке Попытка ... Исключение.
Идея метода заключается в том, что мы программно формируем код, вызывающий нужную процедуру, сохраняем его во временный файл и пробуем открыть форму. Если процедуры нет — срабатывает исключение при открытии внешней формы.
Разберем реализацию функции проверки:
Функция ЕстьПроцедураГМ(ИмяПроцедуры, КоличествоПараметров)
Перем Путь, Имя;
РасположениеФайла(Путь, Имя);
ФС.УстТекКаталог(Путь);
// Формируем список фиктивных параметров для вызова
ТекстПараметров = "";
Для Сч = 1 По КоличествоПараметров Цикл
ТекстПараметров = ТекстПараметров + ?(ТекстПараметров = "", "", ",") + "1";
КонецЦикла;
// Формируем модуль, который немедленно закрывается при успехе
ТекстОбработки = СоздатьОбъект("Текст");
ТекстОбработки.ДобавитьСтроку("Процедура ПриОткрытии() СтатусВозврата(0); КонецПроцедуры");
ТекстОбработки.ДобавитьСтроку(ИмяПроцедуры + "(" + ТекстПараметров + ");");
ИмяФайла = Путь + "CheckProc.txt";
ТекстОбработки.Записать(ИмяФайла);
// Пытаемся открыть проверочную обработку (использующую директиву #ЗагрузитьИзФайла)
Попытка
ОткрытьФорму("Отчет",, Путь + "CheckProc.ert");
Возврат 1; // Процедура успешно скомпилировалась и существует
Исключение
Возврат 0; // Процедуры нет в конфигурации
КонецПопытки;
КонецФункции
При использовании этого приема форма отчета CheckProc.ert сразу отменяет свое открытие через СтатусВозврата(0), пользователь не видит мерцания окон, а результат проверки позволяет безопасно решить, какой алгоритм запускать далее.
Если в системе разрешено использование популярной внешней компоненты 1С++, задача решается значительно проще и быстрее, без обращения к диску и файловой системе.
Проанализируем пример перехвата компиляции с помощью объекта ВыполняемыйМодуль:
Модуль = СоздатьОбъект("ВыполняемыйМодуль");
Модуль.УстановитьМодуль("Рез = глПредставлениеДокумента(КонтекстДокумента);");
Попытка
Модуль.КомпилироватьМодуль();
Модуль.ВыполнитьМодуль();
Исключение
// Процедура отсутствует — выполняем локальный альтернативный алгоритм
Сообщить("Глобальная функция не найдена, используется локальный расчет", "I");
КонецПопытки;
Метод КомпилироватьМодуль() генерирует штатное перехватываемое исключение, если вызываемая процедура не найдена в таблице глобальных символов программы, что позволяет легко управлять потоком выполнения.
Еще один вариант валидации без применения внешних библиотек — использование OLE-соединения с текущей информационной базой через объект V77.Application. При вычислении выражения через EvalExpr обращение к отсутствующей функции генерирует COM-ошибку, которая корректно перехватывается блоком Попытка ... Исключение и не засоряет интерактивное окно сообщений пользователя.
Для создания универсальных обработок в 1С 7.7 оптимально использовать комбинацию методов:
Метаданные.ВыполняемыйМодуль.