Предотвратить процесс "A" от запуска процесса "B", который затем отображается поверх того, что должно быть "TopMost" процесс "C"

У меня есть приложение Windows Form, которое должно быть TopMost. Я установил свою форму как TopMost, и мое приложение работает так, как мне хотелось бы, за исключением одного случая.

Существует стороннее приложение (называемое player.exe), которое отображает SWF-файлы фильмов в той части экрана, которая появляется в верхней части моего приложения.

Используя Process Monitor, я определил, что приложение player.exe вызывает
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
в моем случае:
flash.exe 901 96 379 261 somemovie.swf

Так как flash.exe создается в новом процессе, после того как моя форма установлена ​​в TopMost, она появляется поверх моего приложения.

Первым делом я заставил свое приложение свернуть главное окно player.exe, надеясь, что это также предотвратит появление Flash. Но, к сожалению, это не так... даже если свернуть окно при каждом запуске флэш-ролика, оно отображается в пиксельном местоположении (901,96). Затем я попытался создать таймер для установки значения свойства form.TopMost в значение true каждые 10 мс. Это работает, но вы все еще видите очень быстрый всплеск файла SWF.

Существует ли какой-то тип вызова Windows API, который можно использовать для временного предотвращения появления player.exe от дочерних процессов, которые являются видимыми? Я признаю, что это звучит немного надуманным. Но, любопытно, если у кого-то еще была подобная проблема.


Приложение:

Это дополнение должно дать ответ на некоторые из предложений, изложенных в посте Мэтью ниже.

Для чрезвычайной ситуации, описанной в комментариях, я бы посмотрел на возможные решения в этом направлении:

1) Как обычно запускается и останавливается стороннее приложение? Могу ли я закрыть его так же? Если это служба, диспетчер управления службами может остановить ее. Если это обычное приложение, отправка управляющего нажатия клавиши (возможно, с SendInput()) или сообщения WM_CLOSE в главное окно может работать.

Самый простой способ закрыть приложение - нажать CTRL-ALT-DEL, а затем убить процесс. -ИЛИ- Правильный способ - удерживать ESC, нажимая левую кнопку мыши..., затем ввести свое имя пользователя и пароль, перемещаться по некоторым меню, чтобы остановить игрока.

Нет команды ПАУЗА... верите или нет.

Я не думаю, что использование WM_CLOSE поможет, так как сворачивание приложения не помогает. Это также убило бы процесс? Если нет, то как вы открываете его?

2) Если я не могу закрыть его, могу ли я его убить? Если это так, TerminateProcess() должен работать.

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

3) Если мне абсолютно необходимо оставить другой процесс запущенным, я бы попытался программно вызвать быстрое переключение пользователей, чтобы перенести меня в другой сеанс (в котором не будет конкурирующих верхних окон). Я не знаю, где в API начать с этого. (Питер Рудерман предлагает для этого SwitchDesktop().)

Я был очень взволнован этой идеей... Я нашел эту статью в CodeProject, который предоставляет множество методов API Wrapper. Я перестал реализовывать это, потому что я думаю, что для того, чтобы рабочий стол работал, у вас должен быть запущен explorer.exe (чего у меня нет).

РЕДАКТИРОВАТЬ 2: Если подумать... может быть, файл explorer.exe не нужен. Я попробую и доложу.

Edit3: не удалось получить код в этой статье работает. Придется приостановить это на мгновение.


Сводка ответа

Как и следовало ожидать, нет простого ответа на эту проблему. Лучшим решением было бы проблематично переключиться на другой рабочий стол, когда вам нужно гарантировать, что на нем ничего не появится. Я не смог найти простую C# реализацию переключения рабочего стола, и у меня возникло сомнение, что я просто открою целый новый набор червей, как только он будет реализован. Поэтому я решил не реализовывать коммутацию рабочего стола. Я нашел реализацию C++, которая хорошо работает. Пожалуйста, опубликуйте работающие реализации C# для виртуальных рабочих столов для других.

3 ответа

Решение

Установка свойства TopMost (или добавление стиля WS_EX_TOPMOST к окну) не делает его уникальным в системе. Любое количество верхних окон может быть создано любым количеством приложений; единственная гарантия состоит в том, что все самые верхние окна будут нарисованы над всеми не верхними окнами. Если есть два или более верхних окна, Z-порядок все еще применяется. Из вашего описания я подозреваю, что flash.exe также создает самое верхнее окно.

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

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

Приложение:

Для чрезвычайной ситуации, описанной в комментариях, я бы посмотрел на возможные решения в этом направлении:

  1. Как стороннее приложение обычно запускается и останавливается? Могу ли я закрыть его так же? Если это служба, диспетчер управления службами может остановить ее. Если это обычное приложение, отправка управляющего нажатия клавиши (возможно, с SendInput()) или сообщения WM_CLOSE в главное окно может работать.

  2. Если я не могу закрыть его, могу ли я его убить? Если это так, TerminateProcess () должен работать.

  3. Если мне абсолютно необходимо оставить другой процесс запущенным, я бы попытался программно вызвать быстрое переключение пользователей, чтобы перенести меня в другой сеанс (в котором не будет конкурирующих верхних окон). Я не знаю, где в API начать с этого. (Питер Рудерман предлагает для этого SwitchDesktop().)

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

Изменить: после прочтения вашего ответа на комментарий Мэтью, я бы предложил создать новый рабочий стол и переключиться на него, прежде чем отображать ваше предупреждение. (См. CreateDesktop и SwitchDesktop в MSDN.)

Вы можете использовать класс Process для непосредственного запуска flash.exe - и использовать соответствующие параметры ProcessStartInfo, чтобы показать окно в скрытом состоянии - или с WindowStyle, скрытым или свернутым.

Вы также можете рассмотреть возможность использования API-интерфейса SetWindowsHookEx для перехвата вызовов API запуска процесса, и, когда процесс является flash.exe, запустите некоторый код, чтобы вернуть ваше окно в самое верхнее состояние.

Другие вопросы по тегам