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:
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:
whereas it was behind the main form without the ModalPopupMode := pmAuto
.
So I'm hoping these changes will help the (as yet unreproduced) problem.
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.