Delphi - how to find out which modal dialogue has focus and bring it to the fore?

I have a Delphi 2006 application that can display a modal dialog box in response to an error condition. It seems that he is in a state where one of these modal dialogs is open, positioned in front of the main form, but not one of the forms responds to messages. Pressing the button gives "bonk". The application works fine, the user interface updates the main form, but you can not do anything. I think that there is the most likely other modal dialogue in the main form. Whether this is one of mine or one of Windows, I have no idea.

Other items:

  • The application responds to OK shortcuts. One of these short circuits gracefully closes the application and it worked. Since then, I have not been able to reproduce the situation.
  • The application has a tray icon. This responds to right clicks. If I hide the application here, the main form minimizes and leaves the displayed modal dialog still without focus. If I restore the main form, everything happens as it was, and not a single window has focus. Alt-Tab have similar results. Platform
  • is Windows 7
  • I call DisableProcessWindowsGhosting before creating any forms.
  • I open modal dialogs with

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

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

My question has two parts:

Is there a way to programmatically find out which window has focus? Then I could take some action for this scenario, or as a last resort, I could provide them with a shortcut to the foreground or take some evasive actions (depending on the dialog), for example, set ModalResult to mrCancel.

How could such a situation arise? Usually, when I get a modal dialog behind the main form (I can do this by opening the modal dialog, minimizing the application from the tray icon, and then restoring the application again - the main form of the application is restored before the dialog, the dialog still retains focus), I can bring it back to the forefront by clicking on the tray icon or closing it with the Esc , but in this case it does not work.

** UPDATE **

Misha fix worked separately from non-delphi dialogs like TSaveDialog. I was able to get them to work by adding Application.ModalPopupMode := pmAuto ; immediately before calling Execute .

By β€œgetting it to work,” I mean that the save dialog was ahead after the following sequence:

  • open save dialog
  • Minimize application from tray icon
  • restore application from tray icon

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

Therefore, I hope that these changes will help the (not yet recreated) problem.

+7
source share
4 answers

The last active popup (VCL or not) can be requested using 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 a bit copied from TApplication.BringToFront .

Bringing this window to the beginning can be done using SetForegroundWindow :

 SetForegroundWindow(GetTopWindow); 

Note that Application.BringToFront can generally do the trick, but once I experienced that it is not working properly, a situation that I could not reproduce, though.

+4
source

If a form with focus takes too long to respond to messages (Form1), so that Windows thinks that Form1 is not responding, and Form1 displays a modal form (Form2), after displaying Form 2, and the application processes the messages again, Form1 will be transferred to the front, which potentially β€œcovers” form 2.

Put this in the Application.OnIdle event, doing the trick:

  if Assigned(Screen.ActiveForm) then begin if (fsModal in Screen.ActiveForm.FormState) and (Application.DialogHandle <= 0)) then begin Screen.ActiveForm.BringToFront; end; end; 
+5
source

GetForegroundWindow () is the function you are looking for, if you know the name or have a modal window handle, it's simple.

HWND GetForegroundWindow ();

Gets the handle of the foreground window (the window with which the user is currently working). The system assigns a slightly higher priority to the thread, which creates a foreground window than it does for other threads.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms633505%28v=vs.85%29.aspx

0
source

I used the Mishas solution and did a bit of work (using the NGLNs code) to solve the problems detected by rossmcm (images without a VCL dialog).

The following code is executed: timer:

 type TCustomFormAccess = class(TCustomForm); if Assigned(Screen.ActiveCustomForm) then begin if ((fsModal in Screen.ActiveCustomForm.FormState) and (Application.DialogHandle <= 0)) then begin TopWindow := GetLastActivePopup(Application.Handle); TopWindowForm := nil; for i := 0 to Screen.CustomFormCount - 1 do begin CustomFormAccess := TCustomFormAccess(Screen.CustomForms[i]); if CustomFormAccess.WindowHandle = TopWindow then TopWindowForm := CustomFormAccess; end; if Assigned(TopWindowForm) and (Screen.ActiveCustomForm.Handle <> TopWindow) then begin Screen.ActiveCustomForm.BringToFront; end; end; end; 
0
source

All Articles