Как перехватить контекст активной формы или открытого табличного документа в 1С (Обычное приложение)?

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

Зачастую перед разработчиками 1С встает задача взаимодействия с уже открытыми окнами в интерфейсе пользователя. Одной из самых популярных задач является желание добавить глобальную кнопку (например, в общее меню Интерфейса), которая позволила бы отправлять любые открытые печатные формы (табличные документы) по электронной почте, без необходимости вносить изменения в код формирования каждого отдельного отчета или печатной формы. В старых версиях платформы, таких как 1С 7.7, эта задача легко решалась с помощью внешней компоненты FormEx. Давайте разберем, как обстоят дела в 1С:Предприятие 8 в режиме обычного приложения и какие способы решения у нас есть.

Разберем ограничения платформы 1С 8.x

Многие разработчики, переходя на 8-ю версию платформы, пытаются найти встроенную функцию наподобие ActiveWindow или АктивныйКонтекст(). Посмотрим, почему стандартные подходы не всегда работают:

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

Решение 1: Использование единой формы печати (Архитектурный подход)

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

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

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

  1. Создаем или находим в конфигурации общую форму для печати документов.
  2. В эту форму добавляем нашу кнопку «Отправить по электронной почте».
  3. При формировании любой печатной формы в коде обращаемся к этой общей форме, передаем в нее сформированный табличный документ и открываем ее.
  4. В самой форме код кнопки будет иметь прямой доступ к элементу ЭлементыФормы.ПолеТабличногоДокумента, и проблема перехвата контекста полностью исчезает. Мы четко понимаем, с какими данными работаем.

Решение 2: Обходной путь через глобальную переменную (Саморегистрация форм)

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

Разберем реализацию этого алгоритма:

  1. В модуле обычного приложения (или в глобальном общем модуле с кэшированием) заводим глобальную переменную типа Массив (например, глОткрытыеФормы).
  2. В процедуре ПриОткрытии() каждой нужной формы мы добавляем ссылку на саму себя в этот массив:
  3. 
    Процедура ПриОткрытии()
        глОткрытыеФормы.Добавить(ЭтаФорма);
    КонецПроцедуры
    
  4. В обработчике ПриЗакрытии() обязательно удаляем форму из массива, чтобы не вызывать утечек памяти и обращений к несуществующим объектам:
  5. 
    Процедура ПриЗакрытии()
        Индекс = глОткрытыеФормы.Найти(ЭтаФорма);
        Если Индекс <> Неопределено Тогда
            глОткрытыеФормы.Удалить(Индекс);
        КонецЕсли;
    КонецПроцедуры
    
  6. Теперь, когда нам нужно получить активную форму (например, из глобального меню), мы просто обращаемся к последнему элементу нашего глобального массива глОткрытыеФормы, так как он будет содержать последнюю открытую форму.

Важно: Главный минус данного подхода — необходимость вносить модификации в модули абсолютно всех форм конфигурации, контекст которых мы хотим перехватывать.

Решение 3: Использование внешних компонент (ВК)

Проанализируем альтернативный путь для тех, кто не хочет менять логику конфигурации. Для 8-й версии платформы существуют внешние компоненты (аналоги FormEx) и разработки на базе 1С++ или WinAPI. Они позволяют получить хэндл (HWND) активного системного окна Windows и попытаться извлечь оттуда данные.

Однако использовать системные перехватчики в 8.x для получения программного объекта 1С крайне сложно и нестабильно. Платформа 1С 8.x отрисовывает интерфейс самостоятельно, и напрямую конвертировать системное окно Windows в объект типа ТабличныйДокумент средствами 1С нельзя. Мы настоятельно не рекомендуем этот подход для решения типовых бизнес-задач, так как он приводит к падениям платформы и проблемам при обновлениях платформы.

Подводим итоги

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

← На главную