Как предотвратить потерю фокуса окном 1С при запуске внешних приложений?

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

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

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

Выясним причину: почему фокус ведет себя по-разному?

Проанализируем ситуацию с точки зрения операционной системы. Разница в поведении обработчиков (событие НачалоВыбора и нажатие кнопки) обусловлена тем, как платформа 1С управляет модальностью и визуальным состоянием (например, при запуске на полный экран):

  1. Обработчик выбора файла: Когда срабатывает этот метод, система часто находится в состоянии ожидания диалога. Это состояние заставляет ОС удерживать фокус на родительском приложении более жестко.
  2. Нажатие кнопки: Это обычное событие. Если мы используем ЗапуститьПриложение() с параметром Истина (ожидание завершения), поток 1С фактически "засыпает". Когда внешняя программа завершается, Windows должна решить, какое окно сделать активным. Поскольку процесс 1С долгое время не отвечал на запросы отрисовки (был заблокирован ожиданием), ОС может посчитать его "неприоритетным" и передать фокус приложению, которое было активно до запуска 1С.

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

Способ 1. Использование COM-объекта WScript.Shell со скрытым окном

Стандартная КомандаСистемы() часто вызывает кратковременное появление черного окна консоли (cmd), что само по себе провоцирует ОС на переключение контекста. Мы можем использовать объект WScript.Shell, который позволяет запустить приложение в скрытом режиме. Это минимизирует вмешательство в работу графического интерфейса.

Разберем пример кода:


Процедура ОбработатьФайлЧерезWShell(ИмяФайла)
    // Создаем объект оболочки Windows
    WshShell = Новый COMОбъект("WScript.Shell");
    
    // Формируем строку запуска
    // 0 - запустить в скрытом окне
    // Истина - ждать завершения работы приложения
    КодВозврата = WshShell.Run(СтрокаЗапуска, 0, Истина);
    
    Если КодВозврата = 0 Тогда
        Сообщить("Файл успешно обработан");
    КонецЕсли;
КонецПроцедуры

Использование параметра 0 вместо 1 (нормальное окно) часто является ключевым фактором сохранения фокуса.

Способ 2. Принудительная активация окна через AppActivate

Если скрытый запуск не помог, мы можем явно приказать операционной системе вернуть фокус нашему приложению. Для этого используется метод AppActivate того же COM-объекта WScript.Shell. В качестве параметра методу нужно передать заголовок окна или идентификатор процесса.

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


Процедура ВыполнитьСВозвратомФокуса()
    // 1. Запоминаем текущий заголовок окна 1С
    ЗаголовокПриложения = ПолучитьЗаголовокПриложения();
    
    // 2. Выполняем внешнюю операцию
    ЗапуститьПриложение(СтрокаЗапуска, , Истина);
    
    // 3. Возвращаем фокус
    Оболочка = Новый COMОбъект("Wscript.Shell");
    Оболочка.AppActivate(ЗаголовокПриложения);
    
    // 4. Для надежности активизируем форму программно
    ЭтаФорма.Активизировать();
КонецПроцедуры

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

Способ 3. Использование обработчика ожидания (самый надежный метод)

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

Посмотрим на пример реализации:


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

Процедура ПринудительноВернутьФокус() Экспорт
    // Этот код сработает через 0.1 сек после того, как 1С освободится
    ЭтаФорма.Активизировать();
    
    // Можно также использовать запуск пустого предупреждения с таймаутом, 
    // если форма все еще не на переднем плане
    // ПоказатьОповещениеПользователя("Обработка завершена");
КонецПроцедуры

Способ 4. Запуск через PowerShell с параметром Hidden

Современные версии Windows позволяют использовать PowerShell для более тонкого управления процессами. Мы можем обернуть вызов нашей утилиты в команду Start-Process с параметром -WindowStyle Hidden. Это работает стабильнее, чем классический cmd.

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


ПутьКПрограмме = "C:\Utils\converter.exe";
Аргументы = "-input file.pdf -output file.txt";

// Формируем команду для PowerShell
КомандаPS = "powershell -windowstyle hidden -command ""& {Start-Process '" + ПутьКПрограмме + "' -ArgumentList '" + Аргументы + "' -Wait}""";

ЗапуститьПриложение(КомандаPS, , Истина);

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

Резюме и рекомендации

Мы рассмотрели несколько подходов к решению проблемы "улетающего" фокуса. Подведем итоги:

  1. Если вам нужно просто выполнить команду без вывода окна, используйте WScript.Shell с параметром окна 0.
  2. Если проблема сохраняется, используйте Обработчик ожидания на 0.1 или 0.2 секунды для вызова ЭтаФорма.Активизировать(). Это даст операционной системе время завершить все внутренние переключения.
  3. Проверяйте контекст исполнения: если вызов уходит НаСервер, а потом возвращается на клиент, фокус может теряться из-за особенностей работы тонкого или веб-клиента. В обычных формах (как в УТ 10.3) старайтесь держать логику запуска внешней программы в клиентских процедурах модуля формы.

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

← На главную