Как устранить аварийное завершение 1С при вызове ЗавершитьРаботуСистемы() по таймауту

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

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

Анализ технической причины ошибки

Разберем ситуацию: когда мы используем метод ПоказатьВопрос с указанием таймаута, платформа 1С запускает внутренний таймер. Если пользователь не успевает нажать кнопку, система сама вызывает процедуру оповещения. Ошибка BEX (Buffer Overflow Exception) в сочетании с StackHash указывает на то, что происходит попытка выполнения кода в области памяти, которая защищена механизмом DEP (Data Execution Prevention).

Проанализируем механику процесса: в момент срабатывания таймаута стек вызовов платформы еще занят обработкой диалогового окна. Если в этот же момент вызывается ЗавершитьРаботуСистемы(), происходит конфликт потоков, и программа пытается обратиться к уже освобожденному или защищенному адресу памяти. Это классическая ошибка доступа (Access Violation, код c0000005), которую мы видим в дампе ошибки.

Программный обход проблемы через обработчик ожидания

Наиболее надежный способ избежать падения платформы — это «разорвать» поток выполнения. Мы не должны вызывать закрытие системы напрямую из процедуры обработки оповещения, если она вызвана таймаутом. Вместо этого мы дадим платформе доли секунды, чтобы штатно закрыть все окна и очистить стек.

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

Посмотрим на пример реализации кода в модуле формы:


&НаКлиенте
Процедура ПослеЗакрытияВопроса(Результат, Параметры) Экспорт
    
    Если Результат = КодВозвратаДиалога.Таймаут Или Результат = КодВозвратаДиалога.Да Тогда
        // Вместо ЗавершитьРаботуСистемы(Ложь) используем разрыв через обработчик
        ПодключитьОбработчикОжидания("ВыполнитьБезопасноеЗавершениеРаботы", 0.1, Истина);
    КонецЕсли;
    
КонецПроцедуры

&НаКлиенте
Процедура ВыполнитьБезопасноеЗавершениеРаботы() Экспорт
    
    // Теперь, когда стек чист, закрываем систему
    ЗавершитьРаботуСистемы(Ложь);
    
КонецПроцедуры

&НаКлиенте
Процедура ПриОткрытии(Отказ)
    
    Режим = РежимДиалогаВопрос.ДаНет;
    Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияВопроса", ЭтаФорма);
    ПоказатьВопрос(Оповещение, "Завершить работу?", Режим, 5); // 5 секунд таймаут
    
КонецПроцедуры

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

Настройка системы предотвращения выполнения данных (DEP)

Если программный метод не помогает или вы используете версию платформы, где ошибка проявляется даже при простых действиях, необходимо настроить операционную систему. Ошибка BEX часто возникает на серверных ОС (например, Windows Server 2008 R2 или 2012), где политика безопасности более жесткая.

Выполним следующие шаги для настройки исключений:

  1. Откроем Панель управления — Система — Дополнительные параметры системы.
  2. Перейдем на вкладку Дополнительно и в разделе Быстродействие нажмем кнопку Параметры.
  3. Выберем вкладку Предотвращение выполнения данных (DEP).
  4. Если выбран вариант «Включить DEP для всех программ и служб, кроме выбранных ниже», нам нужно добавить исполняемые файлы 1С в список исключений.
  5. Нажмем кнопку Добавить и укажем пути к файлам 1cv8.exe и 1cv8c.exe (обычно они находятся в папке C:\Program Files (x86)\1cv8\номер_версии\bin\).
  6. Применим изменения и перезагрузим компьютер (или серверную сессию).

Важный момент: на 64-битных операционных системах 32-битный клиент 1С более подвержен ошибкам типа StackHash. Если ваша инфраструктура позволяет, рассмотрите возможность перехода на 64-битный клиентский софт 1С, так как он работает с памятью более стабильно.

Версии платформы и библиотеки Microsoft Visual C++

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

Выясним, на что еще стоит обратить внимание:

  1. Обновление платформы: Если вы столкнулись с ошибкой на версии 8.3.5, переход на стабильные релизы (например, 8.3.6 и выше) может решить проблему, так как в них изменен механизм работы с объектами оповещения.
  2. Библиотеки Visual C++: Платформа 1С активно использует распространяемые пакеты Microsoft Visual C++ Redistributable. Например, версия 8.3.14 требует корректной установки пакета 2017 года. Если установка была повреждена или установлена несовместимая версия (например, x64 вместо x86 для 32-битного клиента), это может приводить к ошибкам при выгрузке модулей из памяти. Рекомендуется переустановить соответствующие пакеты с официального сайта Microsoft.
  3. Очистка кэша: Иногда в кэше пользователя сохраняются настройки форм или окон, которые платформа пытается записать в момент закрытия. Если кэш поврежден, ЗавершитьРаботуСистемы вызовет сбой. Попробуйте полностью удалить базу из списка и добавить её заново для очистки локальных временных файлов.

Влияние аппаратного ускорения

В редких случаях, особенно при работе через терминальный сервер (RDP), ошибка StackHash при закрытии графических окон может быть вызвана драйвером видеокарты или включенным аппаратным ускорением графики. Рассмотрим вариант решения через запуск 1С с параметрами. Можно попробовать запустить клиент с ключом /NoFrame или временно отключить аппаратное ускорение в настройках Windows, чтобы проверить, исчезнет ли ошибка.

Подводя итог, можно сказать, что наиболее «чистым» и профессиональным решением со стороны разработчика 1С является использование обработчика ожидания. Это гарантирует стабильную работу программы вне зависимости от настроек DEP на конкретном компьютере пользователя.

← На главную