1
votes

I have a Form that is shown modal from the MainForm. In this modal form I override the WM_SYSCOMMAND like this :

protected
  procedure WMSysCommand(var Msg: TWMSysCommand);  message WM_SYSCOMMAND;

procedure TModalDlg.WMSysCommand(var Msg: TWMSysCommand);
begin
 if (fsModal in FormState) and (Msg.CmdType and $FFF0 = SC_MINIMIZE)
  then Application.MainForm.WindowState:= wsMinimized
  else inherited;
end;

... and when I minimize the modal form, the whole application is minimized. Everything is ok, but when I click on the taskbar button and the application is restored, the foscused window is the MainForm, not the modal one, like it should. What should I do to restore the app with the most modal form focused ?

1
Try calling Application.Minimize() instead of setting Application.MainForm.WindowState to wsMinimized. Application.Minimize() performs additional tasks to remember active windows and focus and such, which Application.Restore() then restoresRemy Lebeau
Unfortunately no Application.Restore here because there's no system command. Modal form does not receive a wm_syscommand because the taskbar button belongs to the main form. The main form does not receive it either because it is disabled. In fact I'm surprised the application is restored.Sertac Akyuz
Anyway, the only message you can hook into is the wm_windowposchanging on the main form. You can fire a timer and wait for the main form's restore animation to finish and then activate the modal form. Very poor solution. Animation time is not definite either, does not help at all. Change your design, do not minimize when there is a modal form. Or arrange a taskbar button for the modal form.Sertac Akyuz
@RemyLebeau, Application.Minimize is the first thing I tried. But this has a bug. On the first Minimize/Restore, when I click the taskbar button, the application is not restored (nothing happens), I must click one more time to restore it. And now I see that it doesn't set the correct focus either.Marus Gradinaru

1 Answers

1
votes

In your current design you have a taskbar button for a minimized window which is disabled because of the modal form. I don't think you will be able to work out a sensible solution for this setup, neither form receives a WM_SYSCOMMAND - modal form because it doesn't have a taskbar button and the main form because it is disabled.

Change your strategy and switch taskbar buttons when you are minimizing the modal form. That is, you'll have a taskbar button for the modal form and not for the main form. You can then intercept and reverse in the same event handler when you receive a restore command. Below is a working example, but I should note that changing the window owner of a window after it has been created is strongly discouraged and in fact not documented any more for quite some time.


type
  TModalDlg = class(TForm)
    ...
  private
    FParentWnd: HWND;
  protected
    procedure WMSysCommand(var Msg: TWMSysCommand); message WM_SYSCOMMAND;
  end;

...

procedure TModalDlg.WMSysCommand(var Msg: TWMSysCommand);
begin
  if (fsModal in FormState) then begin
    case Msg.CmdType and $FFF0 of
      SC_MINIMIZE:
        begin
          SetWindowLong(Handle, GWL_EXSTYLE,
              (GetWindowLong(Handle, GWL_EXSTYLE) or WS_EX_APPWINDOW));

          FParentWnd := GetWindowLong(Handle, GWL_HWNDPARENT);
          if FParentWnd <> 0 then
            ShowWindow(FParentWnd, SW_HIDE);

          SetWindowLong(Handle, GWL_HWNDPARENT, 0);
        end;
      SC_RESTORE:
        begin
          SetWindowLong(Handle, GWL_EXSTYLE,
              (GetWindowLong(Handle, GWL_EXSTYLE) and not WS_EX_APPWINDOW));

          if FParentWnd <> 0 then begin
            SetWindowLong(Handle, GWL_HWNDPARENT, FParentWnd);
            ShowWindow(FParentWnd, SW_SHOW);
          end;
        end;
    end;
  end;
  inherited;
end;