11

I have a utility dialog (non-modal and stay-on-top) that should be accessible at all times when using the application (think of a dialog that can be used to take notes while working with the application) even if a modal dialog is displayed.

The rest of the application cannot be changed.

Is it possible? How could I go about it?

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
jpfollenius
  • 16,456
  • 10
  • 90
  • 156
  • 'Modality' in Windows can indeed be a PITA. (The worst example I can think of is Microsoft Word 2010, where you cannot open a Word document (e.g. by double-clicking a *.docx file) if some other Word window has a modal dialog open.) Perhaps your utility form could be part of a different application? – Andreas Rejbrand Oct 18 '12 at 11:33
  • @Andreas Rejbrand: I thought about making it a separate application but I need to have access to the applications internals (for some capture / replay mechanism). – jpfollenius Oct 18 '12 at 11:49
  • Using named pipes for communication between two applications is pretty easy. Look at [cromis-ipc](http://www.cromis.net/blog/downloads/cromis-ipc/) for a good start. – LU RD Oct 18 '12 at 12:16
  • @Andreas Rejbrand: is that a "no, not possible" from you? – jpfollenius Oct 18 '12 at 13:09

1 Answers1

18

When ShowModal is called, all existing top level windows are disabled. That's how modality is meant to work. If you have a window with which interaction is reasonable, you just need to enable it again.

For example, you could add this to your utility window:

type
  TMyUtilityForm = class(TForm)
  protected
    procedure WMEnable(var Message: TWMEnable); message WM_ENABLE;
  end;
....
procedure TMyUtilityForm.WMEnable(var Message: TWMEnable);
begin
  if not Message.Enabled then
    EnableWindow(Handle, True);
  inherited;
end;

This will make sure that your utility window can never be disabled.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • 1
    @AndreasRejbrand Very nice of you to say so, and I can only wish it were actually true! ;-) – David Heffernan Oct 18 '12 at 15:05
  • I'd use a `WM_ENABLE` handler, and a call to `EanbleWindow()` before the inherited call. Would look more natural. – Sertac Akyuz Oct 18 '12 at 17:59
  • @Sertac I agree that this mechanism to avoid disabling could be cleaner. I just put in the first idea that came into my head to demonstrate the basic concept. – David Heffernan Oct 19 '12 at 06:40
  • 1
    +1 David, thank you so much for this! This works nicely and saves me so much effort. Thanks a lot! – jpfollenius Oct 19 '12 at 06:56
  • 2
    I would add `if not IsWindowEnabled(Handle)` however, because otherwise it starts to look like an infinite loop, even though `EnableWindow(Handle, True)` probably won't result in a `WM_ENABLE` to be sent in case the window is already enabled. – Thijs van Dien Oct 30 '12 at 15:51
  • @tvdien Done. It's actually easiest to read the Enabled state out of the message that is passed to you. And no, there's no infinite recursion here. `EnableWindow` only leads to `WM_ENABLE` if the state is being altered. – David Heffernan Oct 30 '12 at 16:00
  • @DavidHeffernan: I know that this wasn't in the original question, but the above doesn't work with MDI. With MDI, the WMEnable handler of the non-modal never seems to be called. Any ideas how to solve this? – No'am Newman Mar 02 '14 at 16:38
  • @No'am Perhaps a new question? – David Heffernan Mar 02 '14 at 17:04