При разработке функционала автоматического выхода пользователей из системы часто возникает неприятная ситуация: программа корректно закрывается при нажатии кнопки в диалоговом окне, но «вылетает» с критической ошибкой BEX или StackHash, если закрытие инициируется по истечении времени ожидания (таймаута). В этой статье мы подробно разберем, почему это происходит, и рассмотрим эффективные методы решения данной проблемы.
Разберем ситуацию: когда мы используем метод ПоказатьВопрос с указанием таймаута, платформа 1С запускает внутренний таймер. Если пользователь не успевает нажать кнопку, система сама вызывает процедуру оповещения. Ошибка BEX (Buffer Overflow Exception) в сочетании с StackHash указывает на то, что происходит попытка выполнения кода в области памяти, которая защищена механизмом DEP (Data Execution Prevention).
Проанализируем механику процесса: в момент срабатывания таймаута стек вызовов платформы еще занят обработкой диалогового окна. Если в этот же момент вызывается ЗавершитьРаботуСистемы(), происходит конфликт потоков, и программа пытается обратиться к уже освобожденному или защищенному адресу памяти. Это классическая ошибка доступа (Access Violation, код c0000005), которую мы видим в дампе ошибки.
Наиболее надежный способ избежать падения платформы — это «разорвать» поток выполнения. Мы не должны вызывать закрытие системы напрямую из процедуры обработки оповещения, если она вызвана таймаутом. Вместо этого мы дадим платформе доли секунды, чтобы штатно закрыть все окна и очистить стек.
Рассмотрим, как изменить стандартный код. Вместо прямого вызова команды закрытия, мы подключим однократный обработчик ожидания.
Посмотрим на пример реализации кода в модуле формы:
&НаКлиенте
Процедура ПослеЗакрытияВопроса(Результат, Параметры) Экспорт
Если Результат = КодВозвратаДиалога.Таймаут Или Результат = КодВозвратаДиалога.Да Тогда
// Вместо ЗавершитьРаботуСистемы(Ложь) используем разрыв через обработчик
ПодключитьОбработчикОжидания("ВыполнитьБезопасноеЗавершениеРаботы", 0.1, Истина);
КонецЕсли;
КонецПроцедуры
&НаКлиенте
Процедура ВыполнитьБезопасноеЗавершениеРаботы() Экспорт
// Теперь, когда стек чист, закрываем систему
ЗавершитьРаботуСистемы(Ложь);
КонецПроцедуры
&НаКлиенте
Процедура ПриОткрытии(Отказ)
Режим = РежимДиалогаВопрос.ДаНет;
Оповещение = Новый ОписаниеОповещения("ПослеЗакрытияВопроса", ЭтаФорма);
ПоказатьВопрос(Оповещение, "Завершить работу?", Режим, 5); // 5 секунд таймаут
КонецПроцедуры
В данном примере использование метода ПодключитьОбработчикОжидания с интервалом 0.1 секунды позволяет платформе корректно завершить внутренние процессы обработки диалога. Параметр Истина гарантирует, что обработчик выполнится только один раз.
Если программный метод не помогает или вы используете версию платформы, где ошибка проявляется даже при простых действиях, необходимо настроить операционную систему. Ошибка BEX часто возникает на серверных ОС (например, Windows Server 2008 R2 или 2012), где политика безопасности более жесткая.
Выполним следующие шаги для настройки исключений:
1cv8.exe и 1cv8c.exe (обычно они находятся в папке C:\Program Files (x86)\1cv8\номер_версии\bin\).Важный момент: на 64-битных операционных системах 32-битный клиент 1С более подвержен ошибкам типа StackHash. Если ваша инфраструктура позволяет, рассмотрите возможность перехода на 64-битный клиентский софт 1С, так как он работает с памятью более стабильно.
Проанализируем влияние версий платформы. Ошибки при закрытии по таймауту были официально зафиксированы в релизах 8.3.5.1460 и некоторых сборках ветки 8.3.14. Техническая поддержка 1С подтверждала наличие багов в логике работы асинхронных вызовов.
Выясним, на что еще стоит обратить внимание:
ЗавершитьРаботуСистемы вызовет сбой. Попробуйте полностью удалить базу из списка и добавить её заново для очистки локальных временных файлов.В редких случаях, особенно при работе через терминальный сервер (RDP), ошибка StackHash при закрытии графических окон может быть вызвана драйвером видеокарты или включенным аппаратным ускорением графики. Рассмотрим вариант решения через запуск 1С с параметрами. Можно попробовать запустить клиент с ключом /NoFrame или временно отключить аппаратное ускорение в настройках Windows, чтобы проверить, исчезнет ли ошибка.
Подводя итог, можно сказать, что наиболее «чистым» и профессиональным решением со стороны разработчика 1С является использование обработчика ожидания. Это гарантирует стабильную работу программы вне зависимости от настроек DEP на конкретном компьютере пользователя.