Почему зависает форма при закрытии в 1С 8.3.27 и как это исправить

Программист 1С v8.3 (Обычные формы) IT и автоматизация бизнеса
← На главную

Разработчики, работающие с Обычным приложением на современных версиях платформы 1С:Предприятие 8.3 (начиная с релизов 8.3.26.1303 и 8.3.27.1326), все чаще сталкиваются с критической проблемой: при попытке программного закрытия формы документа или обработки приложение «зависает намертво». При этом стандартные механизмы перехвата исключений не срабатывают, а отладка прерывается на строке выполнения метода Закрыть(). В этой статье мы подробно разберем, почему это происходит, и рассмотрим проверенные способы обхода данной ошибки.

Анализируем причину зависания: регрессия в ядре платформы

Проанализируем ситуацию: на версии платформы 8.3.25 код работает корректно, а на последующих обновлениях возникают сбои. Это явный признак регрессии — ошибки, возникшей в результате изменений в самом движке 1С. Основная причина кроется в глубокой модернизации графического стека и механизмов работы с памятью, которые в новых версиях ориентированы на Управляемые формы и мобильную платформу.

Рассмотрим основные факторы, провоцирующие «deadlock» (взаимную блокировку) интерфейса:

  1. Обновление движка HTML: В последних релизах 8.3 был обновлен встроенный компонент отображения веб-контента. Если на форме присутствует поле HTML-документа, обращение к нему или закрытие формы с таким объектом в обычном приложении часто приводит к краху потока отрисовки.
  2. Конфликт обработчиков событий: При вызове Закрыть() платформа инициирует цепочку событий ПередЗакрытием и ПриЗакрытии. В новых версиях ядра возникает ситуация, когда фокус ввода или системные сообщения Windows не могут быть корректно переданы между родительским и дочерним окнами.
  3. Некорректная идентификация окон: Использование старых методов обращения к формам (включая недокументированное использование стандартных форм) через ссылку в некоторых случаях создает «теневые» экземпляры объектов, которые блокируют основной поток при попытке их уничтожения.

Способ 1. Корректное получение формы через коллекцию окон

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


Форма = Ссылка.ПолучитьФорму("ФормаДокумента");
Если Форма.Открыта() Тогда
    Форма.Закрыть();
КонецЕсли;

Проблема заключается в том, что метод ПолучитьФорму() без указания ключа уникальности или владельца в новых версиях платформы может не найти уже существующее на экране окно, а создать новый программный объект, связанный с той же ссылкой. Попытка закрыть такой объект, когда основное окно еще активно, вызывает конфликт дескрипторов HWND.

Вместо этого мы рекомендуем использовать поиск по открытым окнам клиентского приложения. Разберем правильный подход:


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

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

Способ 2. Использование обработчика ожидания для разрыва стека вызовов

Зачастую зависание происходит из-за того, что команда Закрыть() вызывается в тот момент, когда платформа еще занята обработкой другого события (например, нажатия кнопки или изменения поля). Мы можем применить «трюк» с асинхронным вызовом, чтобы позволить платформе завершить текущие операции перед закрытием окна.

Рассмотрим, как это реализовать. В модуле формы или обработки создадим процедуру для закрытия, а вызывать её будем через ПодключитьОбработчикОжидания.

Шаг 1. В месте, где нужно закрыть форму, пишем:


// Устанавливаем минимальную задержку в 0.1 секунды
ПодключитьОбработчикОжидания("ВыполнитьЗакрытиеФормыПрограммно", 0.1, Истина);

Шаг 2. Описываем саму процедуру:


Процедура ВыполнитьЗакрытиеФормыПрограммно() Экспорт
    ЭтаФорма.Закрыть();
КонецПроцедуры

Этот подход позволяет полностью очистить программный стек и избежать ситуации, когда один и тот же поток пытается одновременно отрисовать изменения в форме и уничтожить её объект.

Способ 3. Проверка режима совместимости и диагностика HTML-компонентов

Если ваша конфигурация «сильно переделана», как указано в исходном вопросе, проверьте наличие в формах устаревших ActiveX элементов или специфических настроек оформления. Проанализируем ситуацию с режимом совместимости. Даже если вы устанавливаете значение «Версия 8.3.25», физический исполняемый файл платформы 8.3.27 использует новые библиотеки отрисовки (GDI+/DirectX).

Рекомендации по диагностике:

Итоговые выводы и рекомендации

Подведем итоги нашего исследования. Если вы столкнулись с «мертвым» зависанием обычных форм на новых релизах 1С 8.3:

  1. Первым делом проверьте, не вызвано ли это спецификой метода ПолучитьФорму(). Перейдите на поиск окон через ПолучитьОкнаКлиентскогоПриложения().
  2. Если прямое закрытие вешает систему, используйте ПодключитьОбработчикОжидания для выноса команды закрытия из текущего потока выполнения.
  3. Для критически важных бизнес-процессов, где стабильность обычного приложения превыше всего, рассмотрите возможность отката на стабильную версию платформы 8.3.25.1394. На текущий момент ветка 8.3.27 содержит ряд неразрешенных проблем совместимости с «неуправляемым» интерфейсом.

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

← На главную