Почему Спр.Выбрать() в 1С 7.7 открывается немодально и как это исправить?

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

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

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

Выясняем причину возникновения псевдомодальности

Для того чтобы эффективно бороться с проблемой, нам необходимо понять физику процесса. Каким образом старая платформа 1С 7.7 организует модальность? На уровне операционной системы Windows модальность реализуется через временное отключение ввода для родительских окон. Платформа 1С использует для этого стандартную системную функцию Windows API под названием EnableWindow. Когда открывается модальный диалог, родительское окно переводится в состояние disabled, и все сообщения мыши и клавиатуры перенаправляются в активное модальное окно.

Проанализируем основные факторы, которые ломают этот механизм в современных условиях:

  1. Изменение логики работы Windows API в современных ОС. Платформа 1С:Предприятие 7.7 разрабатывалась во времена Windows 98/2000/XP. Начиная с Windows Vista и заканчивая Windows 10/11, за отрисовку окон отвечает диспетчер Desktop Window Manager (DWM). При включенных эффектах Aero, прозрачности интерфейса или аппаратном ускорении вызов функции EnableWindow может отрабатывать некорректно. Визуально окно выглядит заблокированным, но физически клики мыши продолжают «просачиваться» сквозь него.
  2. Особенности работы в RDP и RemoteApp. При публикации 1С 7.7 через терминальный сервер синхронизация модальных состояний между сервером и клиентом часто ломается. Протокол RDP передает геометрию окон независимо. Если на сервере окно считается отключенным, клиентский терминал может не успеть обработать событие потери фокуса, из-за чего фокус «проваливается» на задний план, оставляя интерфейс доступным для кликов.
  3. Влияние внешних компонент (ВК). Такие библиотеки, как FormEx или 1С++, расширяют возможности стандартного интерфейса за счет установки глобальных системных перехватчиков (хуков) мыши и клавиатуры. Если внешняя компонента некорректно обрабатывает события фокуса в современной ОС, системный хук начинает перенаправлять клики мимо модального окна на родительскую форму.
  4. Некорректный контекст вызова в коде. Внутренний цикл обработки сообщений платформы 1С может рассинхронизироваться, если модальный диалог вызывается из критических процедур:
    • Внутри предопределенной процедуры ПриОткрытии(), когда форма-владелец еще не успела полностью инициализироваться в операционной системе.
    • В процедурах, запускаемых по таймеру через ОбработкаОжидания(), когда модальный цикл стартует вне контекста интерактивного действия пользователя.
    • При наличии вызова СтатусВозврата(0) в цепочке событий открытия формы.

Ниже мы подробно рассмотрим четыре практических способа решения этой проблемы.

Способ 1. Замена вызова Выбрать на ВвестиЗначение

Если стандартный метод Спр.Выбрать() стабильно дает сбой, наиболее быстрый способ вернуть жесткую модальность — использовать функцию ВвестиЗначение(). Данный метод создает системный диалог выбора на более низком уровне платформы, что гарантирует стабильное удержание фокуса ввода в операционных системах Windows 7, 10 и 11.

Рассмотрим пример кода, демонстрирующий безопасный вызов окна выбора значения:


// Создаем объект справочника Контрагенты
СпрК = СоздатьОбъект("Справочник.Контрагенты");
ВыбранноеЗначение = "";

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

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

Способ 2. Переход на немодальный режим работы (ОткрытьПодбор)

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

Разберем по шагам, как реализовать этот подход:

Шаг 1. В кодовой базе родительской формы (например, при нажатии кнопки выбора) вызываем форму подбора:


Процедура ПриНажатииКнопкиВыбора()
    // Открываем форму выбора контрагента в режиме подбора
    ОткрытьПодбор("Справочник.Контрагенты", "ФормаСписка", Контекст, 0);
КонецПроцедуры

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


Процедура ОбработкаПодбора(ВыбранноеЗначение, КонтекстПодбора)
    Если ВыбранноеЗначение.Выбран() = 1 Тогда
        Контрагент = ВыбранноеЗначение;
        Сообщить("Выбран контрагент через подбор: " + Контрагент.Наименование);
    КонецЕсли;
КонецПроцедуры

Использование подбора полностью устраняет баг «псевдомодальности», поскольку окно изначально открывается как немодальное. Платформа корректно обрабатывает переключение окон, исключая зависания интерфейса в RDP-сессиях.

Способ 3. Эмуляция модальности через программную блокировку

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

Рассмотрим пример реализации такой блокировки интерфейса:


Процедура УправлятьДоступностьюФормы(СтатусБлокировки)
    // Отключаем или включаем ключевые элементы управления
    Форма.КнопкаПровести.Доступность(1 - СтатусБлокировки);
    Форма.Контрагент.Доступность(1 - СтатусБлокировки);
    Форма.Договор.Доступность(1 - СтатусБлокировки);
КонецПроцедуры

Процедура ВыполнитьВыборСБлокировкой()
    // Блокируем интерфейс текущей формы
    УправлятьДоступностьюФормы(1);
    
    // Запускаем форму подбора немодально
    ОткрытьПодбор("Справочник.Контрагенты", "ФормаСписка", Контекст, 0);
КонецПроцедуры

Процедура ОбработкаПодбора(ВыбранноеЗначение, КонтекстПодбора)
    // Разблокируем интерфейс
    УправлятьДоступностьюФормы(0);
    
    Если ВыбранноеЗначение.Выбран() = 1 Тогда
        Контрагент = ВыбранноеЗначение;
    КонецЕсли;
КонецПроцедуры

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

Способ 4. Корректировка настроек операционной системы и ВК

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

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

← На главную