Apr 092016
 

There was one shortcoming in my Delphi IDE explorer that has irked me since the beginning: It was disabled while a modal dialog was shown in the IDE, so there was no way to inspect the controls on the current dialog. The option to follow the focus ameliorated this a bit because it was now possible to click on the various controls in the dialog and see their properties, but still: There was no way to inspect non-clickable controls and how they were related to other controls on the form or to switch the different pages showing the properties, events, hierarchy or parents of the current control.

Delphi-Ide-Explorer-with-modal-form

(Click on the picture to see an animation how it works.)

Today, I remembered that I had asked a question on StackOverflow a few days ago: Why do modal Delphi forms not receive WM_SYSCOMMAND when the user clicks the task bar button?

In his answer David Heffernan mentioned the Windows API function EnableWindow and that it is being used by the VCL to disable all windows of an application when one of them is shown modally (and re-enable them afterwards). He explicitly warned me to meddle with that “The consequences are somewhat dire.”.

But being who I am, could of course not resist trying it anyway.

When I asked that question it was about a program at work that was showing a modal progress form which I wanted to allow to minimize the application and restore it when the user clicks on the task bar button. It did not work because the WM_SYSCOMMAND message never reached the program while the modal form was active. I worked around this by re-enabling the main window when the application was minimized (so it would receive the WM_SYSCOMMAND message again), and disabling it again once it got restored. It worked, and so far I have not seen any problems with that approach (but that might still be in store for me).

Today, I used a similar approach to enable the IDE explorer window while a modal form is active in the IDE. My first try was a TTimer that every second called EnabledWindow(Self.Handle, True). While this worked, I thought it might be a bit excessive to call that API every second, so I looked for a better place to put this code. How can a plugin be notified when a modal dialog is being shown? It turned out to be quite easy: Hook Screen.OnActiveFormChange, something I have done before.

And lo and behold: It works and again I have not yet experienced any problems with that approach.

EDIT:
As Ondrej Kelle pointed out in his comment on my Google+ post:

Watching for WM_ENABLE with wParam = 0 in your explorer form, checking if Application.ModalLevel > 0 (meaning a ShowModal call is currently executing), and re-enabling yourself might work, too, and you could avoid the Screen.OnActiveFormChange event hook. (Just an idea.)

He even provided an implementation for this:

/// [...]
interface
/// [...]
type
  TForm1 = class(TForm)
    /// [...]
  private
   procedure WMEnable(var _Msg: TWMEnable); message WM_ENABLE;
   /// [...]
  end;
/// [...]
implementation
/// [...]
procedure TExplorerForm.WMEnable(var _Msg: TWMEnable);
begin
  inherited;
  if not _Msg.Enabled and (Application.ModalLevel > 0) then
    EnableWindow(Self.Handle, True);
end;

And yes, it works. One hook less is good. Thanks Ondrey!

Sorry, the comment form is closed at this time.

%d bloggers like this: