Предотвратить процесс «A» от запуска процесса «B», который затем отображается поверх того, что должно быть «TopMost» процесс «C» - PullRequest
0 голосов
/ 15 июля 2009

У меня есть приложение 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) Как обычно запускается стороннее приложение и остановился? Могу ли я закрыть его так же? Если это услуга, то Диспетчер управления службами может остановить это. Если это обычное приложение, отправка escape клавиши (с SendInput () возможно) или WM_CLOSE сообщение в его главное окно может работать.

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

Нет команды PAUSE ... хотите верьте, хотите нет.

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

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

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

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

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

EDIT2 : Если подумать ... возможно, файл explorer.exe не нужен. Я попробую и доложу.

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


Краткое содержание ответа

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

Ответы [ 3 ]

3 голосов
/ 15 июля 2009

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

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

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

Добавление:

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

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

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

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

0 голосов
/ 15 июля 2009

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

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

0 голосов
/ 15 июля 2009

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

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

...