При разработке внешних отчетов и обработок на платформе 1С:Предприятие 8.3 разработчики часто сталкиваются с ситуацией, когда код, идеально работающий при ручном открытии через меню "Файл — Открыть", начинает вести себя непредсказуемо после интеграции в справочник "Дополнительные отчеты и обработки" (БСП). Типичный пример такой проблемы — "исчезновение" или полное игнорирование диалоговых окон, вызываемых с помощью асинхронных методов вроде ПоказатьВопрос в предопределенной процедуре ПриОткрытии.
В этой статье мы подробно разберем, почему возникает этот неприятный эффект, проанализируем внутренние механизмы платформы и Библиотеки стандартных подсистем (БСП), а также рассмотрим два практических способа решения проблемы с готовыми примерами кода.
Для того чтобы понять, почему платформа игнорирует вызов интерактивного диалога, нам необходимо проанализировать цепочку событий, происходящих при инициализации управляемой формы в различных контекстах.
Когда вы открываете файл обработки напрямую через главное меню системы, платформа выполняет операцию в "чистом" контексте. Окно создается, регистрируется в операционной системе и мгновенно получает фокус активности. В этот момент выполнение клиентского метода ПоказатьВопрос в процедуре ПриОткрытии отрабатывает штатно: диалоговое окно успешно привязывается к активному окну формы.
Ситуация кардинально меняется, когда запуск происходит через стандартный механизм БСП ("Дополнительные отчеты и обработки"). В этом случае процесс выглядит гораздо сложнее:
ПриОткрытии.ПриОткрытии, само окно формы на экране еще физически не отображено и не получило окончательный фокус ввода от операционной системы. Параллельно с этим клиентские механизмы БСП продолжают выполнять свои сопутствующие алгоритмы (перенаправление фокуса, закрытие служебных окон, обработка логов).Поскольку современная платформа 1С работает в асинхронном режиме (при выключенном использовании модальных окон), метод ПоказатьВопрос не останавливает выполнение потока кода. Он лишь регистрирует намерение показать окно и мгновенно возвращает управление платформе. Однако из-за того, что целевое окно формы еще не готово или фокус в данный момент перехватывается алгоритмами БСП, платформа совершает аварийный пропуск визуализации диалога. При этом она сразу вызывает процедуру обратного вызова (callback) с пустым результатом или результатом Неопределено.
Именно поэтому в примере автора темы программа сразу же переходила в процедуру ПослеОтветаНаВопросДанныеЗаполнения, минуя показ самого вопроса, и вызывала ошибку деления на ноль, так как условия проверки выбора пользователя (Да/Нет) не выполнялись.
---
Самым простым, надежным и наиболее распространенным способом обхода этой проблемы является искусственная задержка вызова интерактивного окна. Нам нужно позволить платформе 1С и механизмам БСП полностью завершить отрисовку формы и передать ей фокус активности.
Для этого мы воспользуемся встроенным методом ПодключитьОбработчикОжидания. Перенесем вызов процедуры с вопросом из непосредственного тела ПриОткрытии в подключаемую процедуру с минимальным интервалом времени (например, 0.1 секунды).
Рассмотрим по шагам, как будет выглядеть правильная реализация кода в модуле управляемой формы внешней обработки:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Вместо прямого вызова диалога подключаем однократный обработчик ожидания.
// Интервал 0.1 секунды визуально незаметен для пользователя,
// но достаточен для завершения фоновых процессов БСП.
ПодключитьОбработчикОжидания("Подключаемый_ПроверитьДанныеЗаполнения", 0.1, Истина);
КонецПроцедуры
&НаКлиенте
Процедура Подключаемый_ПроверитьДанныеЗаполнения()
// Эта процедура выполнится тогда, когда форма уже отображена на экране
ПроверитьДанныеЗаполнения();
КонецПроцедуры
&НаКлиенте
Процедура ПроверитьДанныеЗаполнения()
Оповещение = Новый ОписаниеОповещения("ПослеОтветаНаВопросДанныеЗаполнения", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Обнаружены данные прошлого заполнения!
|Заполнить таблицу этими данными?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеОтветаНаВопросДанныеЗаполнения(Результат, Параметры) Экспорт
Если Результат = КодВозвратаДиалога.Да Тогда
// Вызываем логику заполнения данных
ЗаполнитьНоменклатуруНаКлиенте();
ИначеЕсли Результат = КодВозвратаДиалога.Нет Тогда
// Очищаем таблицы заполнения
ОчиститьДанныеЗаполнения();
КонецЕсли;
КонецПроцедуры
Указание третьего параметра Истина в методе ПодключитьОбработчикОжидания критически важно: это гарантирует, что процедура выполнится ровно один раз и таймер автоматически отключится, не перегружая систему циклическими вызовами.
---
В некоторых сценариях логика работы требует, чтобы форма вообще не открывалась, если пользователь отвечает отрицательно на стартовый вопрос. В таких случаях классический обработчик ожидания может визуально "моргнуть" формой перед её закрытием.
Профессиональный подход в рамках стандартов разработки 1С заключается в полном отказе от открытия формы на первом шаге и последующем её программном переоткрытии с параметром-флагом. Давайте проанализируем этот алгоритм:
Параметры.ВопросЗадан).Отказ = Истина, завершая процедуру ПриОткрытии, и сразу запускаем асинхронный метод ПоказатьВопрос.ВопросЗадан = Истина.Реализуем данный метод на практике. Обратите внимание, что для внешних обработок, запущенных через БСП, имя формы определяется динамически, поэтому правильнее использовать свойство формы ИмяФормы:
&НаКлиенте
Процедура ПриОткрытии(Отказ)
// Проверяем, был ли уже задан стартовый вопрос
ПроверкаПройдена = Ложь;
Если Параметры.Свойство("ВопросЗадан", ПроверкаПройдена) И ПроверкаПройдена Тогда
// Вопрос уже задавался, продолжаем стандартное открытие формы
Возврат;
КонецЕсли;
// Если мы здесь, значит форма открывается впервые.
// Отменяем текущее открытие и задаем вопрос интерактивно.
Отказ = Истина;
Оповещение = Новый ОписаниеОповещения("ПослеВопросаПриОткрытии", ЭтотОбъект);
ПоказатьВопрос(Оповещение, "Открыть обработку и заполнить форму данными?", РежимДиалогаВопрос.ДаНет);
КонецПроцедуры
&НаКлиенте
Процедура ПослеВопросаПриОткрытии(Результат, ДополнительныеПараметры) Экспорт
// Если пользователь передумал открывать обработку
Если Результат <> КодВозвратаДиалога.Да Тогда
Возврат;
КонецЕсли;
// Если пользователь согласился, открываем форму заново с параметрами
ПараметрыПовторногоОткрытия = Новый Структура;
ПараметрыПовторногоОткрытия.Вставить("ВопросЗадан", Истина);
// Открываем форму по ее динамическому имени (поддерживает контекст БСП)
ОткрытьФорму(ЭтотОбъект.ИмяФормы, ПараметрыПовторногоОткрытия);
КонецПроцедуры
Данный подход считается максимально чистым с точки зрения UX (User Experience), так как исключает появление пустых или недоинициализированных окон на экране пользователя в случае отказа от работы с обработкой.
---
Дополнительно стоит упомянуть важный аспект интеграции внешних обработок в информационные базы. По умолчанию при регистрации внешней обработки в БСП система предлагает запускать ее в безопасном режиме.
Сам по себе безопасный режим платформы не накладывает ограничений на использование интерактивных функций типа ПоказатьВопрос или Предупреждение. Однако в безопасном режиме запрещены любые вызовы внешних COM-объектов, работа с файловой системой сервера и некоторые другие операции. Если внутри вашей процедуры ПриОткрытии или в самом обработчике оповещения содержатся подобные вызовы, они будут заблокированы системой безопасности, что также может прервать корректный стек выполнения и заблокировать вывод окон диалогов.
Если после реализации обработчика ожидания проблема сохраняется, обязательно проверьте настройки безопасности в карточке дополнительной обработки в режиме "1С:Предприятие" и убедитесь, что обработка не падает с неявной ошибкой прав доступа во время фоновой инициализации.