Как в 1С 7.7 определить успешность выполнения внешнего отчета и подавить вывод ошибок

Программист 1С v7.7 IT и автоматизация бизнеса
← На главную

При разработке и сопровождении конфигураций на платформе 1С:Предприятие 7.7 часто возникает задача запуска внешних отчетов и печатных форм из различных мест конфигурации: из формы документа, из журнала документов или из групповых обработок. Типичная проблема заключается в том, что печатная форма может ожидать контекст открытой формы документа, а при вызове из журнала получает прямую ссылку на документ или контекст списка журнала. В результате при вызове метода ОткрытьФормуМодально() выполнение модуля отчета завершается аварийно, в окно сообщений платформы выводится текст ошибки времени исполнения, а вызывающий код не получает встроенными средствами уведомления о сбое.

Разберем, почему стандартные механизмы языка 1С 7.7 ведут себя именно так, и рассмотрим способы отлова сбоев, подавления системных сообщений, а также архитектурно правильные подходы к решению проблемы.

Ограничение штатного механизма Попытка — Исключение

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


Попытка
    ОткрытьФормуМодально("Отчет", Параметры, ИмяФайла);
Исключение
    Предупреждение("Отчет завершился с ошибкой!");
КонецПопытки;

Проанализируем ситуацию: в платформе 1С 7.7 такая конструкция не перехватывает сбои времени выполнения, происходящие внутри открываемого отчета (например, в предопределенной процедуре ПриОткрытии() или в исполняемом теле модуля). Платформа перехватывает ошибку собственным глобальным обработчиком: прерывает инициализацию формы, выводит красное сообщение в окно сообщений и возвращает управление вызывающему коду на следующую строку после вызова ОткрытьФормуМодально(). Блок Исключение при этом не срабатывает, а переданный параметр не успевает модифицироваться отчетом.

Решение 1. Перехват необработанных ошибок с помощью внешней компоненты 1С++

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

Разберем реализацию этого механизма по шагам.

  1. В глобальном модуле объявляем переменные для управления трассировкой и подключаем перехватчик событий при запуске программы.
  2. Включаем необходимые флаги через класс УправлениеНастройками: перехват событий глобального контекста и ускорение TurboBL.
  3. Создаем обработчик Событие_НеобработаннаяОшибка. Чтобы подавить вывод штатного сообщения об ошибке в окно платформы, функция должна возвращать значение 0. Если вернуть 1, сообщение выведется в обычном режиме.

Посмотрим на пример кода в глобальном модуле:


Перем глТрассировкаОшибок Экспорт;
Перем глСписокНеобработанныхОшибок Экспорт;

Процедура ПриНачалеРаботыСистемы()
    ЗагрузитьВнешнююКомпоненту("1cpp.dll");
    
    // Включаем перехват событий глобального контекста
    оНастр = СоздатьОбъект("УправлениеНастройками");
    оНастр.Включить("TurboBL");
    оНастр.Включить("ПерехватитьСобытияГК");
    
    // Инициализируем перехватчик
    Перехватчик = СоздатьОбъект("Перехватчик");
    Перехватчик.ПодключитьСобытие_НеобработаннаяОшибка();
    
    глСписокНеобработанныхОшибок = СоздатьОбъект("СписокЗначений");
    глТрассировкаОшибок = 0;
КонецПроцедуры

Функция Событие_НеобработаннаяОшибка(СообщениеОбОшибке, Маркер, ИмяФайла, Парам4, НомерСтрокиОшибки, Парам6)
    Если глТрассировкаОшибок = 1 Тогда
        глСписокНеобработанныхОшибок.ДобавитьЗначение(СообщениеОбОшибке);
        // Возврат 0 блокирует вывод текста ошибки в стандартное окно сообщений
        Возврат 0;
    КонецЕсли;
    
    // Возврат 1 передает ошибку стандартному обработчику платформы
    Возврат 1;
КонецФункции

Теперь рассмотрим, как организовать вызов внешнего отчета в вызывающей процедуре:


глСписокНеобработанныхОшибок.УдалитьВсе();
глТрассировкаОшибок = 1;

Параметры = СоздатьОбъект("СписокЗначений");
Параметры.ДобавитьЗначение(ТекущийДокумент(), "Документ");

ОткрытьФормуМодально("Отчет", Параметры, КаталогИБ() + "ExtForms\PrnForm.ert");

глТрассировкаОшибок = 0;

Если глСписокНеобработанныхОшибок.РазмерСписка() > 0 Тогда
    Предупреждение("Не удалось сформировать печатную форму из данного режима!");
КонецЕсли;

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

Решение 2. Предварительная валидация типа передаваемого контекста

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

Используем встроенную функцию ТипЗначенияСтр():


ТипКонтекста = ТипЗначенияСтр(ПередаваемыйОбъект);

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

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

Решение 3. Использование универсальной обработки параметра внутри отчета

Если доступ к исходному коду внешних печатных форм открыт, наиболее надежным и универсальным решением будет адаптация процедуры ПриОткрытии() самого внешнего отчета. Проанализируем универсальный шаблон инициализации:


Процедура ПриОткрытии()
    ВходнойПараметр = Форма.Параметр;
    
    // Определяем, ссылка это или контекст формы
    Если ТипЗначенияСтр(ВходнойПараметр) = "ГрупповойКонтекст" Тогда
        Док = ВходнойПараметр.ТекущийДокумент();
    ИначеЕсли ТипЗначенияСтр(ВходнойПараметр) = "Документ" Тогда
        Док = ВходнойПараметр;
    Иначе
        Предупреждение("Не передан документ для печати!");
        СтатусВозврата(0);
        Возврат;
    КонецЕсли;
    
    Попытка
        Печать(Док);
    Исключение
        Сообщить("Ошибка при формировании печатной формы: " + ОписаниеОшибки(), "!");
        СтатусВозврата(0);
        Возврат;
    КонецПопытки;
КонецПроцедуры

В этом случае логика отчета защищена блоком Попытка — Исключение непосредственно внутри процедуры выполнения, а вызов СтатусВозврата(0) корректно прерывает открытие формы без системных аварий.

Решение 4. Штатная очистка окна сообщений

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


ОткрытьФормуМодально("Отчет", Параметры, ИмяФайла);
ОчиститьОкноСообщений();

Метод ОчиститьОкноСообщений() удалит системные сообщения из окна платформы. Однако следует учитывать, что если окно сообщений уже было открыто на экране, пользователь может успеть заметить кратковременное появление текста ошибки.

← На главную