При разработке механизмов интеграции 1С с внешними утилитами (например, конвертерами PDF, парсерами или архиваторами) программисты часто сталкиваются с неприятным эффектом: после вызова внешней команды через ЗапуститьПриложение() или КомандаСистемы() окно 1С теряет фокус, сворачивается или уходит на задний план, пропуская вперед браузер, блокнот или другие открытые приложения. Особенно странно это выглядит, когда в одном случае (например, при выборе файла) фокус сохраняется, а в другом (при нажатии на кнопку) — теряется.
В этой статье мы подробно разберем, почему это происходит, и рассмотрим несколько надежных способов "смазать лыжи" и вернуть фокус родному приложению.
Проанализируем ситуацию с точки зрения операционной системы. Разница в поведении обработчиков (событие НачалоВыбора и нажатие кнопки) обусловлена тем, как платформа 1С управляет модальностью и визуальным состоянием (например, при запуске на полный экран):
ЗапуститьПриложение() с параметром Истина (ожидание завершения), поток 1С фактически "засыпает". Когда внешняя программа завершается, Windows должна решить, какое окно сделать активным. Поскольку процесс 1С долгое время не отвечал на запросы отрисовки (был заблокирован ожиданием), ОС может посчитать его "неприоритетным" и передать фокус приложению, которое было активно до запуска 1С.Рассмотрим способы исправления этой ситуации, начиная от простых и заканчивая более сложными программными методами.
Стандартная КомандаСистемы() часто вызывает кратковременное появление черного окна консоли (cmd), что само по себе провоцирует ОС на переключение контекста. Мы можем использовать объект WScript.Shell, который позволяет запустить приложение в скрытом режиме. Это минимизирует вмешательство в работу графического интерфейса.
Разберем пример кода:
Процедура ОбработатьФайлЧерезWShell(ИмяФайла)
// Создаем объект оболочки Windows
WshShell = Новый COMОбъект("WScript.Shell");
// Формируем строку запуска
// 0 - запустить в скрытом окне
// Истина - ждать завершения работы приложения
КодВозврата = WshShell.Run(СтрокаЗапуска, 0, Истина);
Если КодВозврата = 0 Тогда
Сообщить("Файл успешно обработан");
КонецЕсли;
КонецПроцедуры
Использование параметра 0 вместо 1 (нормальное окно) часто является ключевым фактором сохранения фокуса.
Если скрытый запуск не помог, мы можем явно приказать операционной системе вернуть фокус нашему приложению. Для этого используется метод AppActivate того же COM-объекта WScript.Shell. В качестве параметра методу нужно передать заголовок окна или идентификатор процесса.
Рассмотрим по шагам, как это реализовать:
Процедура ВыполнитьСВозвратомФокуса()
// 1. Запоминаем текущий заголовок окна 1С
ЗаголовокПриложения = ПолучитьЗаголовокПриложения();
// 2. Выполняем внешнюю операцию
ЗапуститьПриложение(СтрокаЗапуска, , Истина);
// 3. Возвращаем фокус
Оболочка = Новый COMОбъект("Wscript.Shell");
Оболочка.AppActivate(ЗаголовокПриложения);
// 4. Для надежности активизируем форму программно
ЭтаФорма.Активизировать();
КонецПроцедуры
Важный момент: ПолучитьЗаголовокПриложения() возвращает строку, которая должна точно совпадать с текстом в верхней части окна. Если в заголовке меняются данные (например, название базы или текущий документ), убедитесь, что вы берете актуальное значение непосредственно перед вызовом внешней программы.
Иногда попытка активировать окно происходит "слишком рано", когда ОС еще не завершила процесс переключения задач после закрытия внешнего приложения. В таких случаях отлично помогает Обработчик ожидания. Мы даем 1С "продышаться" доли секунды, прежде чем требовать фокус обратно.
Посмотрим на пример реализации:
Процедура КнопкаВыполнитьНажатие(Кнопка)
// Выполняем длительную операцию
Результат = ОбработатьФайл(ИмяФайла);
// Вместо мгновенной активации, ставим задачу в очередь
ПодключитьОбработчикОжидания("ПринудительноВернутьФокус", 0.1, Истина);
КонецПроцедуры
Процедура ПринудительноВернутьФокус() Экспорт
// Этот код сработает через 0.1 сек после того, как 1С освободится
ЭтаФорма.Активизировать();
// Можно также использовать запуск пустого предупреждения с таймаутом,
// если форма все еще не на переднем плане
// ПоказатьОповещениеПользователя("Обработка завершена");
КонецПроцедуры
Современные версии 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С:Предприятия.
Мы рассмотрели несколько подходов к решению проблемы "улетающего" фокуса. Подведем итоги:
WScript.Shell с параметром окна 0.ЭтаФорма.Активизировать(). Это даст операционной системе время завершить все внутренние переключения.Комбинируя эти методы, вы добьетесь плавности интерфейса и избавите пользователей от необходимости постоянно кликать по иконке 1С на панели задач после каждого выполненного действия.