Homer Jones
Homer Jones

Reputation: 53

In Delphi, how to restore a minimized modal form that is not the main form

In the project source, I detect a previous instance of my app, and open it then terminate the new instance.
Remember, I do this in the project source.
The application has a main form that can open a second modal form. If the second, modal, form is not open when the app is minimized (or the user switches to another application) it works fine.

The old main form is opened and the new instance is terminated. However, if the second modal form is minimized, its parent main form is also minimized. That's good UI behavior.

The problem exists when attempting to restore the modal form by a new instance. I can't seem to get the modal form to restore.
I can restore the main form, however the modal form still has focus, but is hidden.

This prevents any user action on the now visible main form. From the user's point of view, the app is hung.

The modal form's caption does not change, so it's easy to get its handle.
The app has a DataModule, which is created first. I do all the duplicate app testing in the project source after the DM is created, but before any other forms are, and well before Application.Run.
That assures that the handles I acquire come from the existing app.
I've tried:

PreviousHandle := FindWindow(nil, PAnsiChar('Form Editor'))
  ShowWindow(PreviousHandle,SW_RESTORE);
  ShowWindow(PreviousHandle,SW_NORMAL);
  BringWindowToTop(PreviousHandle);

The best I've gotten out of variations of this is restoring the main form.

When the handle is for the modal form, it sometimes shows in the lower left as a minimized form.
I say sometimes because I've tried so many variations of the above that I don't remember exactly how this code sample behaved.
All I know is, whatever I've tried from the project source did not restore the modal form, so I tried sending a custom Windows Message to the modal form.
I know the message arrived and the message handler caught it. Example:

  if not PostMessage(PreviousHandle,WM_RESTORE_FORM,PreviousHandle,0) then
      ShowMessage('Can''t automatically show the Form program. '+
            'Please click the taskbar icon.');

Here's what the message handler looks like. It is in the Modal Form. As you can see, I pass the form's handle as a Message param. I've verified that it arrives.
Here's the code in a TApplicationEvents OnMessage event:

procedure TfrmDisplayForm.ApplicationEvents1Message(var Msg: tagMSG;
  var Handled: Boolean);
var
  oldHwnd : THandle;
begin
  if Msg.message = WM_RESTORE_ACORD then
  begin
    oldHwnd := Msg.lParam;
    if ForceForegroundWindow(OldHwnd) then ShowMessage('true') else ShowMessage('False');
    Handled := True;
  end;
end;

Here's the function that is called. However, I've tried various ShowWindows(...) combinations with no luck. Actually, this function didn't do the trick either.

function TfrmDisplayForm.ForceForegroundWindow(hWnd: THandle): BOOL;
var
  hCurWnd: THandle;
begin
{credit Peter Below}
  hCurWnd := GetForegroundWindow;
  AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
     GetCurrentThreadId, True);
  Result := SetForegroundWindow(hWnd);
  AttachThreadInput(GetWindowThreadProcessId(hCurWnd, nil),
     GetCurrentThreadId, False);
end;

I've been working on this for a couple of days, and don't know what I'm doing wrong. Question: How can I restore the modal form? It must be possible because it restores perfectly when the taskbar icon is clicked.

Upvotes: 1

Views: 1136

Answers (1)

SilverWarior
SilverWarior

Reputation: 8331

Don't try to restore individual forms instead use TApplication.Restore

Calling TApplication.Restore will restore all of the application windows to the state before the whole application was minimized same as clicking on TaskBar icon of the application.

PS: I also hope you are not allowing users to minimize individual Modal forms. Or you may also run into a problem where application seems to be stuck.

Upvotes: 1

Related Questions