Search code examples
delphiwindowipcdelphi-2007foreground

How to manage foreground window across processes?


I have two projects which run as separate processes, but belong to the same application:

  • Master (contains TMasterMainForm and TMasterModalForm)
  • Slave (contains TSlaveForm)

The typical way to use this application is like this:

  1. Master is started and shows the TMasterMainForm.
  2. The user can run the slave by clicking a button in TMasterMainForm.
  3. Master starts the Slave process.
  4. Slave shows the TSlaveForm.
  5. Master sends the TForm.Handle of TMasterMainForm to Slave. (via IPC = WM_COPYDATA)

Step 5 is done so that when Slave is closing it can set the foreground window back to TMasterMainForm. This is done to improve the user experience.

This worked fine until we introduced TMasterModalForm.

TMasterModalForm can be started using another button in TMasterMainForm. It is a separate window, but is shown modal and has the TMasterMainForm as its explicit popup parent.

Now when the TSlaveForm is closed the Slave application calls SetForegroundWindow on the handle of the TMasterMainForm, but this is not correct anymore since there is a modal form (TMasterModalForm) on top of it.

So the question is:

How do I manage setting the foreground window in this non trivial situation?

PS: This is a simplified description, the real application is also doing this foreground window stuff the other way around.


Solution

  • You cannot set the foreground window to the master main form because it is disabled. It is disabled because you are showing a modal form whose owner is that main form.

    The obvious solution is to set the foreground window to be the modal form rather than the main form. Since your slave app presumably cannot easily know which window is active, you should re-work your IPC to allow the slave app to ask the master app which window is active, and then make that the foreground window.

    A more elegant solution would be to let the master app call SetForegroundWindow. In fact it would probably be simpler just to call Application.BringToFront from the master process. Of course, the slave process would still need to send a message to the master in order to invoke this. The final piece in the puzzle is dealing with the focus-stealing restrictions but you can do that using AllowSetForegroundWindow. You need your slave process to call this passing the ID of the master process.