Как управлять окном переднего плана между процессами? - PullRequest
3 голосов
/ 22 февраля 2012

У меня есть два проекта, которые выполняются как отдельные процессы, но принадлежат одному приложению:

  • Мастер (содержит TMasterMainForm и TMasterModalForm)
  • Раб (содержит TSlaveForm)

Типичный способ использовать это приложение так:

  1. Мастер запущен и показывает TMasterMainForm.
  2. Пользователь может запустить подчиненное устройство, нажав кнопку в TMasterMainForm.
  3. Мастер запускает подчиненный процесс.
  4. Раб показывает TSlaveForm.
  5. Мастер посылает TForm.Handle из TMasterMainForm Рабу. (через IPC = WM_COPYDATA)

Шаг 5 сделан так, что когда Slave закрывается, он может установить переднее окно на TMasterMainForm. Это сделано для улучшения взаимодействия с пользователем.

Это работало нормально, пока мы не ввели TMasterModalForm.

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

Теперь, когда TSlaveForm закрыто, приложение Slave вызывает SetForegroundWindow для дескриптора TMasterMainForm, но это больше не правильно, поскольку поверх него есть модальная форма (TMasterModalForm).

Так что вопрос:

Как мне управлять настройкой окна переднего плана в этой нетривиальной ситуации?

PS: это упрощенное описание, реальное приложение также выполняет эту работу с окном переднего плана наоборот.

Ответы [ 2 ]

5 голосов
/ 22 февраля 2012

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

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

Более элегантное решение - позволить основному приложению вызвать SetForegroundWindow. На самом деле, вероятно, было бы проще просто вызвать Application.BringToFront из основного процесса. Конечно, подчиненному процессу все равно нужно будет отправить сообщение ведущему, чтобы вызвать это. Последняя часть головоломки посвящена ограничениям кражи фокуса, но вы можете сделать это, используя AllowSetForegroundWindow. Вам нужен ваш подчиненный процесс для вызова этого, передавая идентификатор главного процесса.

3 голосов
/ 22 февраля 2012

Чтобы решить вашу проблему, я бы не стал вызывать SetForegroundWindow из ведомого приложения, а вместо этого отправил бы пользовательское сообщение активации в главное приложение. В этом сообщении вы можете передать нужный дескриптор в WParam или LParam. Основное приложение само может определить, может ли оно активировать этот дескриптор, или вместо этого нужно активировать модальную форму. Вы возлагаете ответственность за активацию правильного окна в самом приложении.

PS: Вам не нужно WM_COPYDATA для отправки дескриптора. Вы можете просто передать в WParam или LParam любое сообщение, которое вы составляете. Это относится к дескриптору для отправки обратно, как я объяснил выше, но также и к дескриптору, который отправляется ведомому в первую очередь.

...