Как сделать так, чтобы окно дочернего процесса казалось модальным в моем процессе? - PullRequest
7 голосов
/ 05 марта 2009

У меня есть приложение, которое вызывает другое служебное приложение, чтобы установить некоторые настройки для определенного устройства. Это служебное приложение вызывается с помощью ShellExecuteEx.

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

Вещи, которые я пробовал:

  1. WaitForSingleObjectEx для процесса после ShellExecuteEx, INFINITE TIMEOUT - окно является модальным, но основное приложение не перерисовывается (потому что ожидает один объект!)
  2. WaitForSingleObjectEx для процесса после ShellExecuteEx, небольшого тайм-аута, затем вызов Peekmessage и DispatchMessage - перерисовка теперь работает, но служебное приложение больше не является «модальным». Основное приложение реагирует на нажатия мыши, нажатия кнопок и т. Д.
  3. EnableWindow (FALSE), затем выполните метод # 2, затем EnableWindow (TRUE) - WORKS !!!, но после этого z-порядок моего приложения изменился. (теперь под другим окном). почему?!

Ответы [ 5 ]

4 голосов
/ 10 марта 2009

У вас есть две вещи для симуляции: владение и модальность.

Для имитации владения: Вам необходимо установить владельца вашего нового окна дочернего процесса в вашем окне. Это должно облегчить любые проблемы с z-порядком. Хотя я не знаю, работает ли это из другого процесса. Если нет, то вам, возможно, придется присоединить свои входные очереди потока и затем вызвать его. Или используйте другой метод внедрения кода.

SetWindowLong <target window handle>, GWL_HWNDPARENT, <new owner handle>

Чтобы имитировать модальность, я думаю, что вы на правильном пути с EnableWindow и WaitForSingleObjectEx.

3 голосов
/ 10 марта 2009

Короткий ответ: нет способа бесшовно сделать окно в потоке B модальным для окна в потоке A, даже если потоки находятся в одном и том же процессе. Если у вас есть код для обоих окон, вы можете приблизиться, но в этом случае вы добьетесь гораздо лучших результатов, поместив весь свой пользовательский интерфейс в один поток.

Если вы попытаетесь предложить пользователю, что окно потока B является модальным для потока A, существует множество тонких Z-порядков и способов активации, которые вы должны исправить (как вы заметили), чтобы не пострадать своего рода эффект долины, когда пользователю ясно, что окно потока B пытается быть тем, чем оно не является, и поэтому кажется сломанным.

Чтобы избежать этого, я бы выбрал такой подход:

  1. Пользователь нажимает на «FDA Inspection» в главном окне canner.exe. canner.exe показывает модальное диалоговое окно, указывающее, что он открывает внешнюю программу («Открытие настроек ботулизма ...»). Это отключает главное окно и т. Д., Чтобы пользователь знал, что происходит модальное взаимодействие.
  2. canner.exe вызывает ShellExecuteEx () для запуска botulism.exe.
  3. canner.exe вызывает WaitForInputIdle () для дескриптора, возвращенного из ShellExecuteEx (). WaitForInputIdle () вернется (приблизительно, но обычно достаточно близко), когда botulsim.exe будет готов к взаимодействию с пользователем. Если botulism.exe обычно показывает пять или более секунд для отображения своего пользовательского интерфейса, я могу использовать короткий цикл с WaitforInputIdle () в цикле и иногда обрабатывать все ожидающие сообщения с помощью PeekMessage () / ProcessMessage ().
  4. canner.exe изменяет текст своего диалогового окна, чтобы отразить, что он ожидает, когда пользователь закроет botulism.exe («Закрыть настройки ботулизма, чтобы продолжить ...»).
  5. canner.exe вызывает MsgWaitForMultipleObjects () в цикле, чтобы дождаться закрытия botulsim.exe. MsgWaitForMultipleObjects () будет возвращаться, когда переданы переданные дескрипторы или когда в очереди потока ожидают сообщения.
  6. Если пользователь нажимает кнопку закрытия в модальном диалоговом окне canner.exe во время ожидания canner.exe, canner.exe запрашивает пользователя о том, что botulism.exe все еще работает («Настройки ботулизма все еще открыты, продолжить в любом случае?», « Да, я знаю "или" Нет, я еще не закончил "). В случае подтверждения canner.exe закрывает диалоговое окно и отменяет первоначальную проверку FDA, начатую на шаге 1, и возвращает к циклу сообщений основного окна.
  7. Когда MsgWaitForMultipleObjects () указывает, что botulism.exe завершен, canner.exe закрывает диалоговое окно и обычно продолжает проверку FDA, начатую на шаге 1.

Таким образом, если все идет нормально и быстро, взаимодействие вполне может быть беспроблемным, но если что-то пойдет не так с дочерним процессом или изменится Z-порядок и т. Д., Будет понятно, почему родительский процесс ожидает и что пользователь должен сделать, чтобы отменить или продолжить задачу, которую он начал.

2 голосов
/ 11 марта 2009

EnableWindow - это правильно, как правило, это делают окна сообщений и другие «модальные» окна. Что касается изменения zorder, вы можете перехватить сообщение WM_WINDOWPOSCHANGING и установить флаг SWP_NOZORDER для предотвращения изменения zorder. Убедитесь, что вы делаете это только при настройке EnableWindow (false).

1 голос
/ 17 марта 2009

Просто логическое предложение,
Возможно, вы сможете создать невидимую модальную форму , и из него использовать метод # 1.

0 голосов
/ 10 марта 2009

Давайте посмотрим на ваш подход № 3, который очень близок к тому, что вы хотите. Я подозреваю, что проблема заключается в том, что когда вторичное приложение закрывается, Windows решает, что не хочет восстанавливать фокус на отключенном окне. Вы можете попытаться повторно включить свое окно до того, как это произойдет, но это может быть сложно (и не стоит усилий).

Вместо того, чтобы отключать окно напрямую, попробуйте отключить его, просто игнорируя пользовательский ввод. Поэтому вместо вызова EnableWindow измените цикл обработки сообщений, чтобы отфильтровать входящие сообщения. В частности, если

msg >= WM_KEYFIRST || msg <= WM_KEYLAST || msg >= WM_MOUSEFIRST || msg <= WM_MOUSELAST

затем отбросить сообщение; в противном случае передайте его в обычный цикл отправки. Что вы делаете, это создаете свое собственное отключенное окно, но Windows не знает этого.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...