Search code examples
formsdelphimodal-dialogdelphi-2009

How to restore a minimized modal form?


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 ?


Solution

  • 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;