Search code examples
delphidelphi-2006

Delphi - how do I find out which modal dialog has focus and bring it to the front?


I have a Delphi 2006 app which can pop up a modal dialog in response to an error condition. It seems to get itself into a state where one of these modal dialogs is open, positioned in front of the main form, but neither form is responding to messages. Clicking on either gives a "bonk". The app is running fine, the UI is updating the main form, but you can't do anything. I guess there is most likely another modal dialog under the main form. Whether it is one of mine or one from Windows I have no idea.

Other points:

  • the app responds to keyboard shortcuts OK. One of these shortuts shuts down the app gracefully and this worked. I have been unable to reproduce the situation since.
  • the app has a tray icon. This responds to right mouse clicks. If I minimize the app from here the main form minimizes and leaves the modal dialog displayed, still without focus. If I restore the main form, things are as they were, with neither window having focus. Alt-tab has similar results.
  • platform is Windows 7
  • I call DisableProcessWindowsGhosting before any forms are created
  • I open the modal dialogs with

    ModalDialog.PopupParent := MainForm ;
    ModalDialog.ShowModal ;
    
  • I postpone these error dialogs if other modal dialogs are open:

    if (Application.ModalLevel = 0) then
        {open modal dialog}
    

My question has two parts:

Is there a way of programmatically finding out what window has focus? I could then take some action for this scenario or a last resort I could them provide a shortcut key to bring it to the front or take some evasive action (depending on the dialog) like set the ModalResult to mrCancel.

How can this situation arise? Normally when I get a modal dialog behind the main form (I can do that by getting the modal dialog to open, minimizing the app from the tray icon, then restoring the app again - the app main form restores in front of the dialog, with the dialog still retaining focus), I can bring it to the front again by clicking on the tray icon, or close it with the Esc key but it didn't work in this case.

**UPDATE**

Misha's fix worked apart from non-delphi dialogs like TSaveDialog. I was able to get them to work as well by adding Application.ModalPopupMode := pmAuto ; just before the call to Execute.

By "got it to work" I mean that the save dialog was in front after the following sequence:

  • open save dialog
  • minimize app from tray icon
  • restore app from tray icon

whereas it was behind the main form without the ModalPopupMode := pmAuto.

So I'm hoping these changes will help the (as yet unreproduced) problem.


Solution

  • The last active popup window (VCL or not) can be queried with GetLastActivePopup:

    function GetTopWindow: HWND;
    begin
      Result := GetLastActivePopup(Application.Handle);
      if (Result = 0) or (Result = Application.Handle) or
          not IsWindowVisible(Result) then
        Result := Screen.ActiveCustomForm.Handle;
    end;
    

    This is somewhat copied from TApplication.BringToFront.

    Bringing this window to the front can be done by SetForegroundWindow:

    SetForegroundWindow(GetTopWindow);
    

    Note that Application.BringToFront might do the trick altogether, but I once experienced it did not function properly, a situation I have not been able to reproduce since though.