Предотвратить процесс "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-порядка, результатом будет мерцающий беспорядок, который пользователь, вероятно, должен будет использовать диспетчер задач, чтобы побег.
Я рекомендую вашей программе не пытаться вмешиваться в другие процессы на компьютере (если это не является ее явным назначением, например, клоном диспетчера задач). Компьютер принадлежит пользователю, и он не может ценить вашу программу более высоко, чем все остальные.
Приложение:
Для чрезвычайной ситуации, описанной в комментариях, я бы посмотрел на возможные решения в этом направлении:
Как стороннее приложение обычно запускается и останавливается? Могу ли я закрыть его так же? Если это служба, диспетчер управления службами может остановить ее. Если это обычное приложение, отправка управляющего нажатия клавиши (возможно, с SendInput()) или сообщения WM_CLOSE в главное окно может работать.
Если я не могу закрыть его, могу ли я его убить? Если это так, TerminateProcess () должен работать.
Если мне абсолютно необходимо оставить другой процесс запущенным, я бы попытался программно вызвать быстрое переключение пользователей, чтобы перенести меня в другой сеанс (в котором не будет конкурирующих верхних окон). Я не знаю, где в API начать с этого. (Питер Рудерман предлагает для этого SwitchDesktop().)
Ответ Мэтью превосходен, но я подозреваю, что вы задаете не тот вопрос. Почему ваше приложение должно быть самым верхним? Если вы пытаетесь создать киоск или что-то в этом роде, то самое главное - не путь.
Изменить: после прочтения вашего ответа на комментарий Мэтью, я бы предложил создать новый рабочий стол и переключиться на него, прежде чем отображать ваше предупреждение. (См. CreateDesktop и SwitchDesktop в MSDN.)
Вы можете использовать класс Process для непосредственного запуска flash.exe - и использовать соответствующие параметры ProcessStartInfo, чтобы показать окно в скрытом состоянии - или с WindowStyle, скрытым или свернутым.
Вы также можете рассмотреть возможность использования API-интерфейса SetWindowsHookEx для перехвата вызовов API запуска процесса, и, когда процесс является flash.exe, запустите некоторый код, чтобы вернуть ваше окно в самое верхнее состояние.