浏览代码

Merge pull request #491 from jrsoftware/rmwindowvisible

rmwindowvisible branch merge
Jordan Russell 8 月之前
父节点
当前提交
658b124f02

+ 2 - 8
Components/BrowseFunc.pas

@@ -86,16 +86,13 @@ begin
       Pointer(lParam) := PChar(InitialDir);
   end;
   ActiveWindow := GetActiveWindow;
-  WindowList := DisableTaskWindows(0);
+  WindowList := DisableTaskWindows(ParentWnd);
   CoInitialize(nil);
   try
     IDList := SHBrowseForFolder(BrowseInfo);
   finally
     CoUninitialize();
     EnableTaskWindows(WindowList);
-    { SetActiveWindow(Application.Handle) is needed or else the focus doesn't
-      properly return to ActiveWindow }
-    SetActiveWindow(Application.Handle);
     SetActiveWindow(ActiveWindow);
   end;
   try
@@ -169,7 +166,7 @@ begin
   ofn.lpstrDefExt := Pointer(DefaultExtension);
 
   ActiveWindow := GetActiveWindow;
-  WindowList := DisableTaskWindows(0);
+  WindowList := DisableTaskWindows(ParentWnd);
   try
     asm
       // Avoid FPU control word change in NETRAP.dll, NETAPI32.dll, etc
@@ -198,9 +195,6 @@ begin
     end;
   finally
     EnableTaskWindows(WindowList);
-    { SetActiveWindow(Application.Handle) is needed or else the focus doesn't
-      properly return to ActiveWindow }
-    SetActiveWindow(Application.Handle);
     SetActiveWindow(ActiveWindow);
   end;
 end;

+ 6 - 4
Components/TaskbarProgressFunc.pas

@@ -48,14 +48,16 @@ const
   StateFlags: array[TTaskbarProgressState] of Integer = (
     TBPF_NOPROGRESS, TBPF_INDETERMINATE, TBPF_NORMAL, TBPF_ERROR, TBPF_PAUSED);
 begin
-  if InitializeTaskbarList then
-    TaskbarListInterface.SetProgressState(Application.Handle, StateFlags[State]);
+  if InitializeTaskbarList and Assigned(Application.MainForm) and
+     Application.MainForm.HandleAllocated then
+    TaskbarListInterface.SetProgressState(Application.MainForm.Handle, StateFlags[State]);
 end;
 
 procedure SetAppTaskbarProgressValue(const Completed, Total: Cardinal);
 begin
-  if InitializeTaskbarList then
-    TaskbarListInterface.SetProgressValue(Application.Handle, Completed, Total);
+  if InitializeTaskbarList and Assigned(Application.MainForm) and
+     Application.MainForm.HandleAllocated then
+    TaskbarListInterface.SetProgressValue(Application.MainForm.Handle, Completed, Total);
 end;
 
 end.

+ 0 - 1
ISHelp/ISHelpGen/UIsxclassesParser.pas

@@ -248,7 +248,6 @@ begin
         end;
       end;
     end;
-    WriteLn(F, '<keyword value="MainForm" />');
     WriteLn(F, '<keyword value="WizardForm" />');
     WriteLn(F, '<keyword value="UninstallProgressForm" />');
   finally

+ 18 - 77
ISHelp/isetup.xml

@@ -1124,18 +1124,10 @@ DefaultGroupName=My Program
 
 <ul appearance="compact">
 <li><link topic="setup_appcopyright">AppCopyright</link></li>
-<li><link topic="setup_backcolor">BackColor</link></li>
-<li><link topic="setup_backcolor">BackColor2</link></li>
-<li><link topic="setup_backcolordirection">BackColorDirection</link></li>
-<li><link topic="setup_backsolid">BackSolid</link></li>
 <li><link topic="setup_flatcomponentslist">FlatComponentsList</link></li>
 <li><link topic="setup_setupiconfile">SetupIconFile</link></li>
 <li><link topic="setup_showcomponentsizes">ShowComponentSizes</link></li>
 <li><link topic="setup_showtaskstreelines">ShowTasksTreeLines</link></li>
-<li><link topic="setup_windowshowcaption">WindowShowCaption</link></li>
-<li><link topic="setup_windowstartmaximized">WindowStartMaximized</link></li>
-<li><link topic="setup_windowresizable">WindowResizable</link></li>
-<li><link topic="setup_windowvisible">WindowVisible</link></li>
 <li><link topic="setup_wizardimagealphaformat">WizardImageAlphaFormat</link></li>
 <li><link topic="setup_wizardimagefile">WizardImageFile</link></li>
 <li><link topic="setup_wizardimagestretch">WizardImageStretch</link></li>
@@ -1151,12 +1143,20 @@ DefaultGroupName=My Program
 
 <ul appearance="compact">
 <li><link topic="setup_alwayscreateuninstallicon">AlwaysCreateUninstallIcon</link></li>
+<li><link topic="setup_windowvisible">BackColor</link></li>
+<li><link topic="setup_windowvisible">BackColor2</link></li>
+<li><link topic="setup_windowvisible">BackColorDirection</link></li>
+<li><link topic="setup_windowvisible">BackSolid</link></li>
 <li><link topic="setup_disableappenddir">DisableAppendDir</link></li>
 <li><link topic="setup_dontmergeduplicatefiles">DontMergeDuplicateFiles</link></li>
 <li><link topic="setup_messagesfile">MessagesFile</link></li>
 <li><link topic="setup_uninstalliconfile">UninstallIconFile</link></li>
 <li><link topic="setup_uninstalliconname">UninstallIconName</link></li>
 <li><link topic="setup_uninstallstyle">UninstallStyle</link></li>
+<li><link topic="setup_windowvisible">WindowResizable</link></li>
+<li><link topic="setup_windowvisible">WindowShowCaption</link></li>
+<li><link topic="setup_windowvisible">WindowStartMaximized</link></li>
+<li><link topic="setup_windowvisible">WindowVisible</link></li>
 <li><link topic="setup_wizardimagebackcolor">WizardImageBackColor</link></li>
 <li><link topic="setup_wizardsmallimagebackcolor">WizardSmallImageBackColor</link></li>
 </ul>
@@ -4032,41 +4032,6 @@ Keep the default set of selected tasks, but deselect the "desktopicon" task:<br/
 </body>
 </setuptopic>
 
-<setuptopic directive="BackColor" title="BackColor, BackColor2">
-<keyword value="BackColor2" />
-<setupvalid>A value in the form of <tt>$<i>bbggrr</i></tt>, where <tt>rr</tt>, <tt>gg</tt>, and <tt>bb</tt> specify the two-digit intensities (in hexadecimal) for red, green, and blue respectively. Or it may be one of the following predefined color names: clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite.</setupvalid>
-<setupdefault><tt>clBlue</tt> for <tt>BackColor</tt>,<br/><tt>clBlack</tt> for <tt>BackColor2</tt></setupdefault>
-<body>
-<p>The <tt>BackColor</tt> directive specifies the color to use at the top (or left, if <tt>BackColorDirection=lefttoright</tt>) of the setup window's gradient background. <tt>BackColor2</tt> specifies the color to use at the bottom (or right).</p>
-<p>The setting of <tt>BackColor2</tt> is ignored if <tt>BackSolid=yes</tt>.</p>
-<examples>
-<pre>
-BackColor=clBlue
-BackColor2=clBlack
-
-BackColor=$FF0000
-BackColor2=$000000
-</pre>
-</examples>
-</body>
-</setuptopic>
-
-<setuptopic directive="BackColorDirection">
-<setupvalid><tt>toptobottom</tt> or <tt>lefttoright</tt></setupvalid>
-<setupdefault><tt>toptobottom</tt></setupdefault>
-<body>
-<p>This determines the direction of the gradient background on the setup window. If <tt>BackColorDirection</tt> is <tt>toptobottom</tt>, it is drawn from top to bottom; if it is <tt>lefttoright</tt>, it is drawn from left to right.</p>
-</body>
-</setuptopic>
-
-<setuptopic directive="BackSolid">
-<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>no</tt></setupdefault>
-<body>
-<p>This specifies whether to use a solid or gradient background on the setup window. If this is <tt>yes</tt>, the background is a solid color (the color specified by <tt>BackColor</tt>; <tt>BackColor2</tt> is ignored).</p>
-</body>
-</setuptopic>
-
 <setuptopic directive="AppName">
 <body>
 <p>This required directive specifies the name of the application being installed. Do not include the version number, as that is defined by the <link topic="setup_appversion">AppVersion</link> and/or <link topic="setup_appvername">AppVerName</link> directives. <tt>AppName</tt> is displayed throughout the Setup program and uninstaller in window titles, wizard pages, and dialog boxes. The value may include constants.</p>
@@ -4165,8 +4130,7 @@ CreateMutex 0&amp;, 0&amp;, "MyProgramsMutexName"
 
 <setuptopic directive="AppCopyright">
 <body>
-<p>Specifies a copyright message that Setup will display in the bottom-right corner of Setup's background window when <link topic="setup_windowvisible">WindowVisible</link> is <tt>yes</tt>.</p>
-<p>The value of this directive is also used as the default value for the <link topic="setup_versioninfocopyright">VersionInfoCopyright</link> directive if it is not specified.</p>
+<p>The value of this directive is used as the default value for the <link topic="setup_versioninfocopyright">VersionInfoCopyright</link> directive if it is not specified.</p>
 <example><pre>AppCopyright=Copyright (C) 1997-2005 My Company, Inc.</pre></example>
 </body>
 </setuptopic>
@@ -5084,39 +5048,16 @@ DiskSliceSize=1457664
 </body>
 </setuptopic>
 
-<setuptopic directive="WindowShowCaption">
-<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>yes</tt></setupdefault>
-<body>
-<p>If set to <tt>no</tt>, Setup will be truly "full screen" -- it won't have a caption bar or border, and it will be on top of the taskbar.</p>
-<p>This directive has no effect if <tt>WindowVisible</tt> is not set to <tt>yes</tt>.</p>
-</body>
-</setuptopic>
-
-<setuptopic directive="WindowStartMaximized">
-<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>yes</tt></setupdefault>
-<body>
-<p>If set to <tt>yes</tt>, the Setup program's background window will initially be displayed in a maximized state, where it won't cover over the taskbar.</p>
-<p>This directive has no effect if <tt>WindowVisible</tt> is not set to <tt>yes</tt>.</p>
-</body>
-</setuptopic>
-
-<setuptopic directive="WindowResizable">
-<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>yes</tt></setupdefault>
-<body>
-<p>If set to <tt>no</tt>, the user won't be able to resize the Setup program's background window when it's not maximized.</p>
-<p>This directive has no effect if <tt>WindowVisible</tt> is not set to <tt>yes</tt>.</p>
-</body>
-</setuptopic>
-
-<setuptopic directive="WindowVisible">
-<setupvalid><link topic="yesnonotes"><tt>yes</tt> or <tt>no</tt></link></setupvalid>
-<setupdefault><tt>no</tt></setupdefault>
+<setuptopic directive="WindowVisible" title="BackColor, BackColor2, BackColorDirection, BackSolid, WindowResizable, WindowShowCaption, WindowStartMaximized, WindowVisible">
+<keyword value="BackColor" />
+<keyword value="BackColor2" />
+<keyword value="BackColorDirection" />
+<keyword value="BackSolid" />
+<keyword value="WindowResizable" />
+<keyword value="WindowShowCaption" />
+<keyword value="WindowStartMaximized" />
 <body>
-<p>If set to <tt>yes</tt>, there will be a gradient background window displayed behind the wizard.</p>
-<p>Note that this is considered a legacy feature; it likely will be removed at some point in the future.</p>
+<p><i>Obsolete in 6.4.</i> These directives are no longer supported. In past versions, they were used to configure a 1990s-style gradient background behind the wizard window. This long-deprecated feature has been removed.</p>
 </body>
 </setuptopic>
 

+ 1 - 2
ISHelp/isxclasses.header2

@@ -1,11 +1,10 @@
 <body>
 
-<p>Below is the list of support classes that can be used from within the Pascal script. There are also three support objects available globally:</p>
+<p>Below is the list of support classes that can be used from within the Pascal script. There are also two support objects available globally:</p>
 
 <ul>
 <li><tt><a name="WizardForm">WizardForm</a></tt> of type <anchorlink name="TWizardForm">TWizardForm</anchorlink>.</li>
 <li><tt><a name="UninstallProgressForm">UninstallProgressForm</a></tt> of type <anchorlink name="TUninstallProgressForm">TUninstallProgressForm</anchorlink>.</li>
-<li><tt><a name="MainForm">MainForm</a></tt> of type <anchorlink name="TMainForm">TMainForm</anchorlink> (only visible if <link topic="setup_windowvisible">WindowVisible</link> is set to <tt>yes</tt>.)</li>
 </ul>
 
 <p>Parameter type <tt>AnyString</tt> means both <tt>String</tt> and <tt>AnsiString</tt> can be used.</p>

+ 0 - 4
ISHelp/isxclasses.pas

@@ -804,10 +804,6 @@ TSetupForm = class(TUIStateForm)
   property SizeAndCenterOnShow: Boolean; read write;
 end;
 
-TMainForm = class(TSetupForm)
-  procedure ShowAboutBox;
-end;
-
 TWizardForm = class(TSetupForm)
   property CancelButton: TNewButton; read;
   property NextButton: TNewButton; read;

+ 11 - 13
ISHelp/isxclasses_wordlists_generated.pas

@@ -27,18 +27,17 @@ var
     'TFolderTreeView', 'TFont', 'TFontStyle', 'TFontStyles', 'TForm', 'TFormBorderStyle',
     'TFormStyle', 'TGraphic', 'TGraphicControl', 'TGraphicsObject', 'THandleStream', 'TInputDirWizardPage',
     'TInputFileWizardPage', 'TInputOptionWizardPage', 'TInputQueryWizardPage', 'TKeyEvent',
-    'TKeyPressEvent', 'TLabel', 'TLinkLabel', 'TListBox', 'TListBoxStyle', 'TMainForm',
-    'TMemo', 'TNewButton', 'TNewCheckBox', 'TNewCheckListBox', 'TNewComboBox', 'TNewEdit',
-    'TNewLinkLabel', 'TNewListBox', 'TNewMemo', 'TNewNotebook', 'TNewNotebookPage', 'TNewProgressBar',
-    'TNewProgressBarState', 'TNewProgressBarStyle', 'TNewRadioButton', 'TNewStaticText',
-    'TNotifyEvent', 'TObject', 'TOutputMarqueeProgressWizardPage', 'TOutputMsgMemoWizardPage',
-    'TOutputMsgWizardPage', 'TOutputProgressWizardPage', 'TPanel', 'TPanelBevel', 'TPasswordEdit',
-    'TPen', 'TPenMode', 'TPenStyle', 'TPersistent', 'TPosition', 'TRadioButton', 'TRichEditViewer',
-    'TScrollingWinControl', 'TScrollStyle', 'TSetupForm', 'TShiftState', 'TSizeConstraints',
-    'TStartMenuFolderTreeView', 'TStream', 'TStringList', 'TStrings', 'TStringStream',
-    'TSysLinkEvent', 'TSysLinkType', 'TUIStateForm', 'TUninstallProgressForm', 'TWinControl',
-    'TWizardForm', 'TWizardPage', 'TWizardPageButtonEvent', 'TWizardPageCancelEvent', 'TWizardPageNotifyEvent',
-    'TWizardPageShouldSkipEvent'
+    'TKeyPressEvent', 'TLabel', 'TLinkLabel', 'TListBox', 'TListBoxStyle', 'TMemo', 'TNewButton',
+    'TNewCheckBox', 'TNewCheckListBox', 'TNewComboBox', 'TNewEdit', 'TNewLinkLabel', 'TNewListBox',
+    'TNewMemo', 'TNewNotebook', 'TNewNotebookPage', 'TNewProgressBar', 'TNewProgressBarState',
+    'TNewProgressBarStyle', 'TNewRadioButton', 'TNewStaticText', 'TNotifyEvent', 'TObject',
+    'TOutputMarqueeProgressWizardPage', 'TOutputMsgMemoWizardPage', 'TOutputMsgWizardPage',
+    'TOutputProgressWizardPage', 'TPanel', 'TPanelBevel', 'TPasswordEdit', 'TPen', 'TPenMode',
+    'TPenStyle', 'TPersistent', 'TPosition', 'TRadioButton', 'TRichEditViewer', 'TScrollingWinControl',
+    'TScrollStyle', 'TSetupForm', 'TShiftState', 'TSizeConstraints', 'TStartMenuFolderTreeView',
+    'TStream', 'TStringList', 'TStrings', 'TStringStream', 'TSysLinkEvent', 'TSysLinkType',
+    'TUIStateForm', 'TUninstallProgressForm', 'TWinControl', 'TWizardForm', 'TWizardPage',
+    'TWizardPageButtonEvent', 'TWizardPageCancelEvent', 'TWizardPageNotifyEvent', 'TWizardPageShouldSkipEvent'
   ];
 
   PascalEnumValues_Isxclasses: array of AnsiString = [
@@ -155,7 +154,6 @@ var
     'procedure SetProgress(Position, Max: Longint);',
     'procedure SetText(Msg1, Msg2: String);',
     'procedure Show;',
-    'procedure ShowAboutBox;',
     'procedure Sort;',
     'procedure TextOut(X, Y: Integer; Text: String);',
     'procedure Update;',

+ 0 - 6
ISHelp/isxfunc.xml

@@ -268,12 +268,6 @@ end;</pre></example>
         <description><p>Returns the <tt>UninstallProgressForm</tt> support object, or raises an internal error if the object has not yet been created.</p></description>
         <seealso><p><link topic="scriptclasses" anchor="UninstallProgressForm">UninstallProgressForm</link></p></seealso>
       </function>
-      <function>
-        <name>GetMainForm</name>
-        <prototype>function GetMainForm: TMainForm;</prototype>
-        <description><p>Returns the <tt>MainForm</tt> support object, or raises an internal error if the object has not yet been created.</p></description>
-        <seealso><p><link topic="scriptclasses" anchor="MainForm">MainForm</link></p></seealso>
-      </function>
     </subcategory>
   </category>
   <category>

+ 28 - 36
Projects/Setup.dpr

@@ -179,29 +179,6 @@ begin
           AcceptedQueryEndSessionInProgress := False;
         Result := True;
       end;
-    WM_STYLECHANGING: begin
-        { On Delphi 2009, we must suppress some of the VCL's manipulation of
-          the application window styles in order to prevent the taskbar button
-          from re-appearing after SetTaskbarButtonVisibility(False) was used
-          to hide it.
-          - The VCL tries to clear WS_EX_TOOLWINDOW whenever a form handle is
-            created (see TCustomForm.CreateParams). Since
-            SetTaskbarButtonVisibility uses the WS_EX_TOOLWINDOW style
-            internally to hide the taskbar button, we can't allow that.
-          - The VCL tries to set WS_EX_APPWINDOW on the application window
-            after the main form is created (see ChangeAppWindow in Forms).
-            The WS_EX_APPWINDOW style forces the window to show a taskbar
-            button, overriding WS_EX_TOOLWINDOW, so don't allow that either.
-            (It appears to be redundant anyway.) }
-        if Integer(Message.WParam) = GWL_EXSTYLE then begin
-          { SetTaskbarButtonVisibility sets TaskbarButtonHidden }
-          if TaskbarButtonHidden then
-            PStyleStruct(Message.LParam).styleNew :=
-              PStyleStruct(Message.LParam).styleNew or WS_EX_TOOLWINDOW;
-          PStyleStruct(Message.LParam).styleNew :=
-            PStyleStruct(Message.LParam).styleNew and not WS_EX_APPWINDOW;
-        end;
-      end;
   end;
 end;
 
@@ -277,17 +254,34 @@ begin
 end;
 
 begin
-  { Delphi 2009 initially sets WS_EX_TOOLWINDOW on the application window.
-    That will prevent our ShowWindow(Application.Handle, SW_SHOW) calls from
-    actually displaying the taskbar button as intended, so clear it. }
-  SetWindowLong(Application.Handle, GWL_EXSTYLE,
-    GetWindowLong(Application.Handle, GWL_EXSTYLE) and not WS_EX_TOOLWINDOW);
-
   try
     SetErrorMode(SEM_FAILCRITICALERRORS);
     DisableWindowGhosting;
     Application.HookMainWindow(TDummyClass.AntiShutdownHook);
     TRichEditViewer.CustomShellExecute := ShellExecuteAsOriginalUser;
+
+    { Don't respect the show command passed by the parent process.
+      "Maximized" makes no sense as our windows don't have maximize/restore
+      buttons, and "Minimized" is problematic as the VCL doesn't realize the
+      app is minimized (Application.Restore has no effect because
+      FAppIconic=False).
+      If the parent process is SetupLdr, then there shouldn't be a non-normal
+      show command because SetupLdr doesn't specify a show command when
+      starting Setup. So this should really only matter when UseSetupLdr=no.
+      First, overwrite the System.CmdShow variable to ensure that
+      Application.Run (if called) doesn't mess with the main form's
+      WindowState.
+      Second, because ShowWindow overrides the value of nCmdShow on the first
+      call if it's SW_SHOWNORMAL, SW_SHOW, or SW_SHOWDEFAULT (which isn't
+      specifically documented; I tested each value), make a first call to
+      ShowWindow here that doesn't actually do anything (the app window is
+      already hidden at this point, and SW_HIDE is not one of the values that
+      get overridden), so that when we show our first form, it will be the
+      second call to ShowWindow and won't have its SW_SHOWNORMAL nCmdShow
+      value overridden. }
+    CmdShow := SW_SHOWNORMAL;
+    ShowWindow(Application.Handle, SW_HIDE);
+
     SelectMode; { Only returns if we should run as Setup }
   except
     { Halt on any exception }
@@ -299,17 +293,15 @@ begin
     Note: There's no need to localize the following line since it's changed in
     InitializeSetup }
   Application.Title := 'Setup';
-  { On Delphi 3+, the application window by default isn't visible until a form
-    is shown. Force it visible like Delphi 2. Note that due to the way
-    TApplication.UpdateVisible is coded, this should be permanent; if a form
-    is shown and hidden, the application window should still be visible. }
-  ShowWindow(Application.Handle, SW_SHOW);
+  Application.ShowMainForm := False;
   Application.OnException := TMainForm.ShowException;
   try
     Application.Initialize;
+    Application.MainFormOnTaskBar := True;
     InitializeSetup;
-    Application.CreateForm(TMainForm, MainForm);
-  MainForm.InitializeWizard;
+    MainForm := TMainForm.Create(Application);
+    Application.CreateForm(TWizardForm, WizardForm);
+    MainForm.InitializeWizard;
   except
     { Halt on any exception }
     ShowExceptionMsg;

+ 0 - 10
Projects/Src/Compiler.ScriptClasses.pas

@@ -311,14 +311,6 @@ begin
   end;
 end;
 
-procedure RegisterMainForm_C(Cl: TPSPascalCompiler);
-begin
-  with CL.AddClassN(CL.FindClass('TSetupForm'), 'TMainForm') do
-  begin
-    RegisterMethod('procedure ShowAboutBox');
-  end;
-end;
-
 procedure RegisterWizardForm_C(Cl: TPSPascalCompiler);
 begin
   with Cl.AddClassN(Cl.FindClass('TSetupForm'), 'TWizardForm') do
@@ -675,7 +667,6 @@ begin
 
   RegisterUIStateForm_C(Cl);
   RegisterSetupForm_C(Cl);
-  RegisterMainForm_C(Cl);
   RegisterWizardForm_C(Cl);
   RegisterUninstallProgressForm_C(Cl);
 
@@ -694,7 +685,6 @@ begin
   RegisterHandCursor_C(Cl);
   
   AddImportedClassVariable(Cl, 'WizardForm', 'TWizardForm');
-  AddImportedClassVariable(Cl, 'MainForm', 'TMainForm');
   AddImportedClassVariable(Cl, 'UninstallProgressForm', 'TUninstallProgressForm');
 end;
 

+ 11 - 42
Projects/Src/Compiler.SetupCompiler.pas

@@ -123,7 +123,7 @@ type
     SetupHeader: TSetupHeader;
 
     SetupDirectiveLines: array[TSetupSectionDirective] of Integer;
-    UseSetupLdr, DiskSpanning, BackSolid, TerminalServicesAware, DEPCompatible, ASLRCompatible: Boolean;
+    UseSetupLdr, DiskSpanning, TerminalServicesAware, DEPCompatible, ASLRCompatible: Boolean;
     DiskSliceSize, DiskClusterSize, SlicesPerDisk, ReserveBytes: Longint;
     LicenseFile, InfoBeforeFile, InfoAfterFile, WizardImageFile: String;
     WizardSmallImageFile: String;
@@ -1653,8 +1653,8 @@ function TSetupCompiler.CheckConst(const S: String; const MinVersion: TSetupVers
 const
   UserConsts: array[0..0] of String = (
     'username');
-  Consts: array[0..42] of String = (
-    'src', 'srcexe', 'tmp', 'app', 'win', 'sys', 'sd', 'groupname', 'commonfonts', 'hwnd',
+  Consts: array[0..41] of String = (
+    'src', 'srcexe', 'tmp', 'app', 'win', 'sys', 'sd', 'groupname', 'commonfonts',
     'commonpf', 'commonpf32', 'commonpf64', 'commoncf', 'commoncf32', 'commoncf64',
     'autopf', 'autopf32', 'autopf64', 'autocf', 'autocf32', 'autocf64',
     'computername', 'dao', 'cmd', 'wizardhwnd', 'sysuserinfoname', 'sysuserinfoorg',
@@ -2579,30 +2579,11 @@ begin
     ssASLRCompatible: begin
         ASLRCompatible := StrToBool(Value);
       end;
-    ssBackColor: begin
-        try
-          SetupHeader.BackColor := StringToColor(Value);
-        except
-          Invalid;
-        end;
-      end;
-    ssBackColor2: begin
-        try
-          SetupHeader.BackColor2 := StringToColor(Value);
-        except
-          Invalid;
-        end;
-      end;
-    ssBackColorDirection: begin
-        if CompareText(Value, 'toptobottom') = 0 then
-          Exclude(SetupHeader.Options, shBackColorHorizontal)
-        else if CompareText(Value, 'lefttoright') = 0 then
-          Include(SetupHeader.Options, shBackColorHorizontal)
-        else
-          Invalid;
-      end;
+    ssBackColor,
+    ssBackColor2,
+    ssBackColorDirection,
     ssBackSolid: begin
-        BackSolid := StrToBool(Value);
+        WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
       end;
     ssChangesAssociations: begin
         SetupHeader.ChangesAssociations := Value;
@@ -3153,17 +3134,11 @@ begin
         if not StrToVersionNumbers(Value, VersionInfoVersion) then
           Invalid;
       end;
-    ssWindowResizable: begin
-        SetSetupHeaderOption(shWindowResizable);
-      end;
-    ssWindowShowCaption: begin
-        SetSetupHeaderOption(shWindowShowCaption);
-      end;
-    ssWindowStartMaximized: begin
-        SetSetupHeaderOption(shWindowStartMaximized);
-      end;
+    ssWindowResizable,
+    ssWindowShowCaption,
+    ssWindowStartMaximized,
     ssWindowVisible: begin
-        SetSetupHeaderOption(shWindowVisible);
+        WarningsList.Add(Format(SCompilerEntryObsolete, ['Setup', KeyName]));
       end;
     ssWizardImageAlphaFormat: begin
         if CompareText(Value, 'none') = 0 then
@@ -7385,7 +7360,6 @@ begin
     SetupHeader.MinVersion.NTVersion := $06010000;
     SetupHeader.MinVersion.NTServicePack := $100;
     SetupHeader.Options := [shDisableStartupPrompt, shCreateAppDir,
-      shWindowStartMaximized, shWindowShowCaption, shWindowResizable,
       shUsePreviousAppDir, shUsePreviousGroup,
       shUsePreviousSetupType, shAlwaysShowComponentsList, shFlatComponentsList,
       shShowComponentSizes, shUsePreviousTasks, shUpdateUninstallLogAppName,
@@ -7398,15 +7372,12 @@ begin
     SetupHeader.UninstallFilesDir := '{app}';
     SetupHeader.DefaultUserInfoName := '{sysuserinfoname}';
     SetupHeader.DefaultUserInfoOrg := '{sysuserinfoorg}';
-    SetupHeader.BackColor := clBlue;
-    SetupHeader.BackColor2 := clBlack;
     SetupHeader.DisableDirPage := dpAuto;
     SetupHeader.DisableProgramGroupPage := dpAuto;
     SetupHeader.CreateUninstallRegKey := 'yes';
     SetupHeader.Uninstallable := 'yes';
     SetupHeader.ChangesEnvironment := 'no';
     SetupHeader.ChangesAssociations := 'no';
-    BackSolid := False;
     DefaultDialogFontName := 'Tahoma';
     SignToolRetryCount := 2;
     SignToolRetryDelay := 500;
@@ -7505,8 +7476,6 @@ begin
     CheckConst(SetupHeader.DefaultUserInfoOrg, SetupHeader.MinVersion, []);
     LineNumber := SetupDirectiveLines[ssDefaultUserInfoSerial];
     CheckConst(SetupHeader.DefaultUserInfoSerial, SetupHeader.MinVersion, []);
-    if BackSolid then
-      SetupHeader.BackColor2 := SetupHeader.BackColor;
     if not DiskSpanning then begin
       DiskSliceSize := MaxDiskSliceSize;
       DiskClusterSize := 1;

+ 23 - 312
Projects/Src/Setup.MainForm.pas

@@ -13,32 +13,19 @@ interface
 
 uses
   Windows, Messages, SysUtils, Classes,
-  Shared.Struct, Setup.MainFunc, Setup.SetupForm, Shared.SetupSteps;
+  Shared.Struct, Setup.MainFunc, Shared.SetupSteps;
 
 type
-  TMainForm = class(TSetupForm)
-    procedure FormResize(Sender: TObject);
-    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
-    procedure FormPaint(Sender: TObject);
-    procedure FormKeyDown(Sender: TObject; var Key: Word;
-      Shift: TShiftState);
+  TMainForm = class(TComponent)
   private
-    IsMinimized, HideWizard: Boolean;
     class procedure AppOnGetActiveFormHandle(var AHandle: HWND);
-    function MainWindowHook(var Message: TMessage): Boolean;
-    procedure UpdateWizardFormVisibility(const IgnoreMinimizedState: Boolean = False);
-    procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
-    procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
-    procedure WMGetDlgCode(var Message: TWMGetDlgCode); message WM_GETDLGCODE;
-    procedure WMShowWindow(var Message: TWMShowWindow); message WM_SHOWWINDOW;
   public
     CurStep: TSetupStep;
-    constructor Create(AOwner: TComponent); override;
     destructor Destroy; override;
+    procedure Close;
     procedure Finish(const FromPreparingPage: Boolean);
     procedure InitializeWizard;
     function Install: Boolean;
-    procedure RestoreApp;
     procedure SetStep(const AStep: TSetupStep; const HandleExceptions: Boolean);
     class procedure ShowException(Sender: TObject; E: Exception);
     class procedure ShowExceptionMsg(const S: String);
@@ -56,176 +43,12 @@ uses
   SetupLdrAndSetup.Messages, SetupLdrAndSetup.RedirFunc, Setup.Install,
   Setup.InstFunc, Setup.WizardForm, Setup.LoggingFunc, Shared.SetupTypes;
 
-{$R *.DFM}
-
-constructor TMainForm.Create(AOwner: TComponent);
-var
-  SystemMenu: HMenu;
-begin
-  inherited;
-
-  InitializeFont;
-
-  if shWindowVisible in SetupHeader.Options then begin
-    { Should the main window not be sizable? }
-    if not(shWindowShowCaption in SetupHeader.Options) then
-      BorderStyle := bsNone
-    else
-    if not(shWindowResizable in SetupHeader.Options) then
-      BorderStyle := bsSingle;
-
-    { Make the main window full-screen. If the window is resizable, limit it
-      to just the work area because full-screen resizable windows don't cover
-      over the taskbar. }
-    BoundsRect := GetRectOfPrimaryMonitor(BorderStyle = bsSizeable);
-    { Before maximizing the window, ensure Handle is created now so the correct
-      'restored' position is saved properly }
-    HandleNeeded;
-
-    { Maximize the window so that the taskbar is still accessible }
-    if shWindowStartMaximized in SetupHeader.Options then
-      WindowState := wsMaximized;
-  end
-  else begin
-    Application.ShowMainForm := False;
-  end;
-
-  if shDisableWelcomePage in SetupHeader.Options then
-    Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppVerName)
-  else
-    Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppName);
-
-  { Append the 'About Setup' item to the system menu }
-  SystemMenu := GetSystemMenu(Handle, False);
-  AppendMenu(SystemMenu, MF_SEPARATOR, 0, nil);
-  AppendMenu(SystemMenu, MF_STRING, 9999, PChar(SetupMessages[msgAboutSetupMenuItem]));
-
-  Application.HookMainWindow(MainWindowHook);
-
-  if Application.ShowMainForm then
-    { Show this form now, so that the focus stays on the wizard form that
-      InitializeWizard (called in the .dpr) shows }
-    Visible := True;
-end;
-
 destructor TMainForm.Destroy;
 begin
-  Application.UnhookMainWindow(MainWindowHook);
+  MainForm := nil;  { just to detect use-after-free }
   inherited;
 end;
 
-procedure TMainForm.WMSysCommand(var Message: TWMSysCommand);
-begin
-  if Message.CmdType = 9999 then
-    ShowAboutBox
-  else
-    inherited;
-end;
-
-procedure TMainForm.WMEraseBkgnd(var Message: TWMEraseBkgnd);
-begin
-  { Since the form paints its entire client area in FormPaint, there is
-    no need for the VCL to ever erase the client area with the brush color.
-    Doing so only slows it down, so this message handler disables that default
-    behavior. }
-  Message.Result := 0;
-end;
-
-procedure TMainForm.FormPaint(Sender: TObject);
-
-  function BlendRGB(const Color1, Color2: TColor; const Blend: Integer): TColor;
-  { Blends Color1 and Color2. Blend must be between 0 and 255; 0 = all Color1,
-    255 = all Color2. }
-  type
-    TColorBytes = array[0..3] of Byte;
-  var
-    I: Integer;
-  begin
-    Result := 0;
-    for I := 0 to 2 do
-      TColorBytes(Result)[I] := Integer(TColorBytes(Color1)[I] +
-        ((TColorBytes(Color2)[I] - TColorBytes(Color1)[I]) * Blend) div 255);
-  end;
-
-var
-  C1, C2: TColor;
-  CS: TPoint;
-  Z: Integer;
-  DrawTextFlags: UINT;
-  R, R2: TRect;
-begin
-  with Canvas do begin
-    { Draw the blue background }
-    if SetupHeader.BackColor = SetupHeader.BackColor2 then begin
-      Brush.Color := SetupHeader.BackColor;
-      FillRect(ClientRect);
-    end
-    else begin
-      C1 := ColorToRGB(SetupHeader.BackColor);
-      C2 := ColorToRGB(SetupHeader.BackColor2);
-      CS := ClientRect.BottomRight;
-      for Z := 0 to 255 do begin
-        Brush.Color := BlendRGB(C1, C2, Z);
-        if not(shBackColorHorizontal in SetupHeader.Options) then
-          FillRect(Rect(0, MulDiv(CS.Y, Z, 255), CS.X, MulDiv(CS.Y, Z+1, 255)))
-        else
-          FillRect(Rect(MulDiv(CS.X, Z, 255), 0, MulDiv(CS.X, Z+1, 255), CS.Y));
-      end;
-    end;
-
-    { Draw the application name and copyright }
-    SetBkMode(Handle, TRANSPARENT);
-
-    DrawTextFlags := DT_WORDBREAK or DT_NOPREFIX or DT_NOCLIP;
-    if RightToLeft then
-      DrawTextFlags := DrawTextFlags or (DT_RIGHT or DT_RTLREADING);
-    SetFontNameSize(Font, LangOptions.TitleFontName,
-      LangOptions.TitleFontSize, 'Arial', 29);
-    if IsMultiByteString(AnsiString(ExpandedAppName)) then
-      { Don't use italics on Japanese characters }
-      Font.Style := [fsBold]
-    else
-      Font.Style := [fsBold, fsItalic];
-    R := ClientRect;
-    InflateRect(R, -8, -8);
-    R2 := R;
-    if RightToLeft then
-      OffsetRect(R2, -4, 4)
-    else
-      OffsetRect(R2, 4, 4);
-    Font.Color := clBlack;
-    DrawText(Handle, PChar(ExpandedAppName), -1, R2, DrawTextFlags);
-    Font.Color := clWhite;
-    DrawText(Handle, PChar(ExpandedAppName), -1, R, DrawTextFlags);
-
-    DrawTextFlags := DrawTextFlags xor DT_RIGHT;
-    SetFontNameSize(Font, LangOptions.CopyrightFontName,
-      LangOptions.CopyrightFontSize, 'Arial', 8);
-    Font.Style := [];
-    R := ClientRect;
-    InflateRect(R, -6, -6);
-    R2 := R;
-    DrawText(Handle, PChar(ExpandedAppCopyright), -1, R2, DrawTextFlags or
-      DT_CALCRECT);
-    R.Top := R.Bottom - (R2.Bottom - R2.Top);
-    R2 := R;
-    if RightToLeft then
-      OffsetRect(R2, -1, 1)
-    else
-      OffsetRect(R2, 1, 1);
-    Font.Color := clBlack;
-    DrawText(Handle, PChar(ExpandedAppCopyright), -1, R2, DrawTextFlags);
-    Font.Color := clWhite;
-    DrawText(Handle, PChar(ExpandedAppCopyright), -1, R, DrawTextFlags);
-  end;
-end;
-
-procedure TMainForm.FormResize(Sender: TObject);
-begin
-  { Needs to redraw the background whenever the form is resized }
-  Repaint;
-end;
-
 procedure TMainForm.ShowAboutBox;
 var
   S: String;
@@ -284,7 +107,6 @@ end;
 
 procedure TMainForm.InitializeWizard;
 begin
-  WizardForm := TWizardForm.Create(Application);
   if CodeRunner <> nil then begin
     try
       CodeRunner.RunProcedures('InitializeWizard', [''], False);
@@ -293,12 +115,11 @@ begin
       raise;
     end;
   end;
-  WizardForm.FlipSizeAndCenterIfNeeded(shWindowVisible in SetupHeader.Options, MainForm, True);
+  WizardForm.FlipSizeAndCenterIfNeeded(False, nil, False);
   WizardForm.SetCurPage(wpWelcome);
   if InstallMode = imNormal then begin
     WizardForm.ClickToStartPage; { this won't go past wpReady  }
-    SetActiveWindow(Application.Handle);  { ensure taskbar button is selected }
-    WizardForm.Show;
+    WizardForm.Visible := True;
   end
   else
     WizardForm.ClickThroughPages;
@@ -340,6 +161,7 @@ function TMainForm.Install: Boolean;
         not NeedsRestart;
       if CheckIfRestartNeeded then
         ChecksumBefore := MakePendingFileRenameOperationsChecksum;
+      var WizardWasHidden := False;
       WindowDisabler := nil;
       try
         for I := 0 to Entries[seRun].Count-1 do begin
@@ -365,15 +187,15 @@ function TMainForm.Install: Boolean;
               WizardForm.StatusLabel.Caption := SetupMessages[msgStatusRunProgram];
             WizardForm.StatusLabel.Update;
             if roHideWizard in RunEntry.Options then begin
-              if WizardForm.Visible and not HideWizard then begin
-                HideWizard := True;
-                UpdateWizardFormVisibility;
+              if WizardForm.Visible and not WizardWasHidden then begin
+                WizardWasHidden := True;
+                WizardForm.Hide;
               end;
             end
             else begin
-              if HideWizard then begin
-                HideWizard := False;
-                UpdateWizardFormVisibility;
+              if WizardWasHidden then begin
+                WizardWasHidden := False;
+                WizardForm.Visible := True;
               end;
             end;
             DebugNotifyEntry(seRun, I);
@@ -383,10 +205,8 @@ function TMainForm.Install: Boolean;
           end;
         end;
       finally
-        if HideWizard then begin
-          HideWizard := False;
-          UpdateWizardFormVisibility;
-        end;
+        if WizardWasHidden then
+          WizardForm.Visible := True;
         WindowDisabler.Free;
         if CheckIfRestartNeeded then begin
           ChecksumAfter := MakePendingFileRenameOperationsChecksum;
@@ -394,7 +214,8 @@ function TMainForm.Install: Boolean;
             NeedsRestart := True;
         end;
       end;
-      Application.BringToFront;
+      if WizardForm.WindowState <> wsMinimized then  { VCL bug workaround }
+        Application.BringToFront;
     end;
   end;
 
@@ -419,7 +240,8 @@ function TMainForm.Install: Boolean;
       finally
         WindowDisabler.Free;
       end;
-      Application.BringToFront;
+      if WizardForm.WindowState <> wsMinimized then  { VCL bug workaround }
+        Application.BringToFront;
 
       if Error = ERROR_FAIL_RESTART then
         Log('One or more applications could not be restarted.')
@@ -453,11 +275,8 @@ begin
       SaveInf(InitSaveInf);
 
     Application.Restore;
-    Update;
-    if InstallMode = imSilent then begin
-      SetActiveWindow(Application.Handle);  { ensure taskbar button is selected }
-      WizardForm.Show;
-    end;
+    if InstallMode = imSilent then
+      WizardForm.Visible := True;
     WizardForm.Update;
 
     SetStep(ssInstall, False);
@@ -514,10 +333,8 @@ begin
       end;
     end;
 
-    if InstallMode = imNormal then begin
+    if InstallMode = imNormal then
       Application.Restore;
-      Update;
-    end;
 
     Result := True;
   except
@@ -653,7 +470,7 @@ begin
   TerminateApp;
 end;
 
-procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
+procedure TMainForm.Close;
 
   function ConfirmCancel(const DefaultConfirm: Boolean): Boolean;
   var
@@ -666,9 +483,6 @@ procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
   end;
 
 begin
-  { Note: Setting CanClose to True causes Application.Terminate to be called;
-    we don't want that. }
-  CanClose := False;
   if Assigned(WizardForm) and WizardForm.HandleAllocated and
      IsWindowVisible(WizardForm.Handle) and IsWindowEnabled(WizardForm.Handle) and
      WizardForm.CancelButton.CanFocus then begin
@@ -689,109 +503,6 @@ begin
   end;
 end;
 
-procedure TMainForm.WMGetDlgCode(var Message: TWMGetDlgCode);
-begin
-  Message.Result := Message.Result or DLGC_WANTTAB;
-end;
-
-function EWP(Wnd: HWND; Param: LPARAM): BOOL; stdcall;
-begin
-  { Note: GetParent is not used here because the other windows are not
-    actually child windows since they don't have WS_CHILD set. }
-  if GetWindowLong(Wnd, GWL_HWNDPARENT) <> Param then
-    Result := True
-  else begin
-    Result := False;
-    BringWindowToTop(Wnd);
-  end;
-end;
-
-procedure TMainForm.FormKeyDown(Sender: TObject; var Key: Word;
-  Shift: TShiftState);
-begin
-  { If, for some reason, the user doesn't have a mouse and the main form was
-    activated, there would normally be no way to reactivate the child form.
-    But this reactivates the form if the user hits a key on the keyboard }
-  if not(ssAlt in Shift) then begin
-    Key := 0;
-    EnumThreadWindows(GetCurrentThreadId, @EWP, Handle);
-  end;
-end;
-
-procedure TMainForm.UpdateWizardFormVisibility(
-  const IgnoreMinimizedState: Boolean = False);
-var
-  ShouldShow: Boolean;
-begin
-  { Note: We don't adjust WizardForm.Visible because on Delphi 3+, if all forms
-    have Visible set to False, the application taskbar button disappears. }
-  if Assigned(WizardForm) and WizardForm.HandleAllocated then begin
-    ShouldShow := WizardForm.Showing and not HideWizard and
-      (IgnoreMinimizedState or not IsIconic(Application.Handle));
-    if (GetWindowLong(WizardForm.Handle, GWL_STYLE) and WS_VISIBLE <> 0) <> ShouldShow then begin
-      if ShouldShow then
-        ShowWindow(WizardForm.Handle, SW_SHOW)
-      else
-        ShowWindow(WizardForm.Handle, SW_HIDE);
-    end;
-  end;
-end;
-
-function TMainForm.MainWindowHook(var Message: TMessage): Boolean;
-var
-  IsIcon: Boolean;
-begin
-  Result := False;
-  case Message.Msg of
-    WM_WINDOWPOSCHANGED: begin
-        { When the application window is minimized or restored, also hide or
-          show WizardForm.
-          Note: MainForm is hidden/shown automatically because its owner
-          window is Application.Handle. }
-        IsIcon := IsIconic(Application.Handle);
-        if IsMinimized <> IsIcon then begin
-          IsMinimized := IsIcon;
-          UpdateWizardFormVisibility;
-        end;
-      end;
-  end;
-end;
-
-procedure TMainForm.WMShowWindow(var Message: TWMShowWindow);
-begin
-  inherited;
-  { When showing, ensure WizardForm is the active window, not MainForm }
-  if Message.Show and (GetActiveWindow = Handle) and
-     Assigned(WizardForm) and WizardForm.HandleAllocated and
-     IsWindowVisible(WizardForm.Handle) then
-    SetActiveWindow(WizardForm.Handle);
-end;
-
-procedure TMainForm.RestoreApp;
-{ Restores the app if it is currently minimized, and tries to make its taskbar
-  button blink (by attempting to bring it to the foreground, which Windows
-  normally blocks). This should be called before displaying any dialogs that
-  aren't user-initiated (like NewDiskForm). }
-begin
-  if IsIconic(Application.Handle) then begin
-    { If called alone, Application.Restore annoyingly brings WizardForm to the
-      foreground even if you're actively clicking/typing in the foreground
-      app. Evidently the SW_RESTORE command used by Application.Restore
-      bypasses Windows' usual foreground-stealing protections. However, if
-      we show WizardForm in advance (and leave the application window still
-      minimized), then SW_RESTORE doesn't bring WizardForm to the foreground
-      (not sure why).
-      Calling ShowWindow(Application.Handle, SW_SHOWNOACTIVATE) before
-      Application.Restore also works, but I worry that's relying on an
-      implementation detail: Application.Restore could be a no-op if it finds
-      the application window isn't minimized. (In fact, it used to be, until
-      the Forms unit added that fake IsIconic function.) }
-    UpdateWizardFormVisibility(True);
-    Application.Restore;
-  end;
-  Application.BringToFront;
-end;
-
 class procedure TMainForm.AppOnGetActiveFormHandle(var AHandle: HWND);
 begin
   { IDE's TMainForm has this too; see comments there }

+ 1 - 59
Projects/Src/Setup.MainFunc.pas

@@ -153,7 +153,6 @@ var
   SetupExitCode: Integer;
   CreatedIcon: Boolean;
   RestartInitiatedByThisProcess, DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages: Boolean;
-  TaskbarButtonHidden: Boolean;
   InstallModeRootKey: HKEY;
 
   CodeRunner: TScriptRunner;
@@ -212,7 +211,6 @@ procedure RemoveTempInstallDir;
 procedure SaveInf(const FileName: String);
 procedure SaveResourceToTempFile(const ResName, Filename: String);
 procedure SetActiveLanguage(const I: Integer);
-procedure SetTaskbarButtonVisibility(const AVisible: Boolean);
 procedure ShellExecuteAsOriginalUser(hWnd: HWND; Operation, FileName, Parameters, Directory: LPWSTR; ShowCmd: Integer); stdcall;
 function ShouldDisableFsRedirForFileEntry(const FileEntry: PSetupFileEntry): Boolean;
 function ShouldDisableFsRedirForRunEntry(const RunEntry: PSetupRunEntry): Boolean;
@@ -1179,12 +1177,6 @@ begin
     else
       Result := PSetupLanguageEntry(Entries[seLanguage][ActiveLanguage]).Name
   end
-  else if Cnst = 'hwnd' then begin
-    if Assigned(MainForm) then
-      Result := IntToStr(MainForm.Handle)
-    else
-      Result := '0';
-  end
   else if Cnst = 'wizardhwnd' then begin
     if Assigned(WizardForm) then
       Result := IntToStr(WizardForm.Handle)
@@ -2235,33 +2227,6 @@ begin
   SetActiveLanguage(I);
 end;
 
-procedure SetTaskbarButtonVisibility(const AVisible: Boolean);
-var
-  ExStyle: Longint;
-begin
-  { The taskbar button is hidden by setting the WS_EX_TOOLWINDOW style on the
-    application window. We can't simply hide the window because on D3+ the VCL
-    would just show it again in TApplication.UpdateVisible when the first form
-    is shown. }
-  TaskbarButtonHidden := not AVisible;  { see WM_STYLECHANGING hook in Setup.dpr }
-  if (GetWindowLong(Application.Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0) <> AVisible then begin
-    SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
-      SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
-    ExStyle := GetWindowLong(Application.Handle, GWL_EXSTYLE);
-    if AVisible then
-      ExStyle := ExStyle and not WS_EX_TOOLWINDOW
-    else
-      ExStyle := ExStyle or WS_EX_TOOLWINDOW;
-    SetWindowLong(Application.Handle, GWL_EXSTYLE, ExStyle);
-    if AVisible then
-      { Show and activate when becoming visible }
-      ShowWindow(Application.Handle, SW_SHOW)
-    else
-      SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
-        SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_SHOWWINDOW);
-  end;
-end;
-
 procedure LogCompatibilityMode;
 var
   S: String;
@@ -2424,14 +2389,6 @@ begin
   RestartInitiatedByThisProcess := True;
   { Note: Depending on the OS, RestartComputer may not return if successful }
   if not RestartComputer then begin
-    { Hack for when called from RespawnSetupElevated: re-show the
-      application's taskbar button } 
-    ShowWindow(Application.Handle, SW_SHOW);
-    { If another app denied the shutdown, we probably lost the foreground;
-      try to take it back. (Note: Application.BringToFront can't be used
-      because we have no visible forms, and MB_SETFOREGROUND doesn't make
-      the app's taskbar button blink.) }
-    SetForegroundWindow(Application.Handle);
     LoggedMsgBox(SetupMessages[msgErrorRestartingComputer], '', mbError,
       MB_OK, True, IDOK);
   end;
@@ -2450,9 +2407,6 @@ var
     NotifyNewLanguage: Integer;
   end;
 begin
-  { Hide the taskbar button }
-  SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
-    SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
   Cancelled := False;
   try
     Server := TSpawnServer.Create;
@@ -2473,11 +2427,8 @@ begin
     { If the user clicked Cancel on the dialog, halt with special exit code }
     if ExceptObject is EAbort then
       Cancelled := True
-    else begin
-      { Otherwise, re-show the taskbar button and re-raise }
-      ShowWindow(Application.Handle, SW_SHOW);
+    else
       raise;
-    end;
   end;
   if Cancelled then
     Halt(ecCancelledBeforeInstall);
@@ -2496,7 +2447,6 @@ begin
     except
       { In the unlikely event that something above raises an exception, handle
         it here so the right exit code will still be returned below }
-      ShowWindow(Application.Handle, SW_SHOW);
       Application.HandleException(nil);
     end;
   end;
@@ -2711,14 +2661,6 @@ var
       InstallMode := imVerySilent
     else if InitSilent then
       InstallMode := imSilent;
-
-    if InstallMode <> imNormal then begin
-      if InstallMode = imVerySilent then begin
-        Application.ShowMainForm := False;
-        SetTaskbarButtonVisibility(False);
-      end;
-      SetupHeader.Options := SetupHeader.Options - [shWindowVisible];
-    end;
   end;
 
   function RecurseExternalGetSizeOfFiles(const DisableFsRedir: Boolean;

+ 2 - 1
Projects/Src/Setup.NewDiskForm.pas

@@ -48,7 +48,8 @@ uses
 function SelectDisk(const DiskNumber: Integer; const AFilename: String;
   var Path: String): Boolean;
 begin
-  MainForm.RestoreApp;
+  Application.Restore;       { see comments in AppMessageBox }
+  Application.BringToFront;  { usually just makes taskbar button blink }
 
   with TNewDiskForm.Create(Application) do
     try

+ 1 - 5
Projects/Src/Setup.RegSvr.pas

@@ -119,9 +119,7 @@ begin
 
   { Set default title; it's set again below after the messages are read }
   Application.Title := 'Setup';
-  { This is needed for D3+: Must force the application window visible since
-    we aren't displaying any forms }
-  ShowWindow(Application.Handle, SW_SHOW);
+  Application.MainFormOnTaskBar := True;
 
   InitializeCommonVars;
 
@@ -133,7 +131,6 @@ begin
     registry entries be in an incomplete/inconsistent state? I'm not sure, so
     a mutex is used here to ensure registrations are serialized. }
   Mutex := Windows.CreateMutex(nil, False, 'Inno-Setup-RegSvr-Mutex');
-  ShowWindow(Application.Handle, SW_HIDE);  { hide taskbar button while waiting }
   if Mutex <> 0 then begin
     { Even though we have no visible windows, process messages while waiting
       so Windows doesn't think we're hung }
@@ -142,7 +139,6 @@ begin
     until MsgWaitForMultipleObjects(1, Mutex, False, INFINITE,
       QS_ALLINPUT) <> WAIT_OBJECT_0+1;
   end;
-  ShowWindow(Application.Handle, SW_SHOW);
   try
     MsgFilename := PathChangeExt(NewParamStr(0), '.msg');
     ListFilename := PathChangeExt(NewParamStr(0), '.lst');

+ 0 - 10
Projects/Src/Setup.ScriptClasses.pas

@@ -202,14 +202,6 @@ begin
   end;
 end;
 
-procedure RegisterMainForm_R(Cl: TPSRuntimeClassImporter);
-begin
-  with CL.Add(TMainForm) do
-  begin
-    RegisterMethod(@TMainForm.ShowAboutBox, 'ShowAboutBox');
-  end;
-end;
-
 procedure RegisterWizardForm_R(Cl: TPSRuntimeClassImporter);
 begin
   with Cl.Add(TWizardForm) do
@@ -444,7 +436,6 @@ begin
 
     RegisterUIStateForm_R(Cl);
     RegisterSetupForm_R(Cl);
-    RegisterMainForm_R(Cl);
     RegisterWizardForm_R(Cl);
     RegisterUninstallProgressForm_R(Cl);
 
@@ -474,7 +465,6 @@ end;
 procedure ScriptClassesLibraryUpdateVars(ScriptInterpreter: TIFPSExec);
 begin
   SetVariantToClass(ScriptInterpreter.GetVarNo(ScriptInterpreter.GetVar('WIZARDFORM')), WizardForm);
-  SetVariantToClass(ScriptInterpreter.GetVarNo(ScriptInterpreter.GetVar('MAINFORM')), MainForm);
   SetVariantToClass(ScriptInterpreter.GetVarNo(ScriptInterpreter.GetVar('UNINSTALLPROGRESSFORM')), UninstallProgressForm);
 end;
 

+ 0 - 9
Projects/Src/Setup.ScriptFunc.HelperFunc.pas

@@ -53,7 +53,6 @@ procedure NoUninstallFuncError(const C: AnsiString); overload;
 procedure OnlyUninstallFuncError(const C: AnsiString); overload;
 function GetMainForm: TMainForm;
 function GetWizardForm: TWizardForm;
-function GetWizardFormHandle: HWND;
 function GetUninstallProgressForm: TUninstallProgressForm;
 function GetMsgBoxCaption: String;
 procedure InitializeScaleBaseUnits;
@@ -125,14 +124,6 @@ begin
     InternalError('An attempt was made to access WizardForm before it has been created');
 end;
 
-function GetWizardFormHandle: HWND;
-begin
-  if Assigned(WizardForm) then
-    Result := WizardForm.Handle
-  else
-    Result := 0;
-end;
-
 function GetUninstallProgressForm: TUninstallProgressForm;
 begin
   Result := UninstallProgressForm;

+ 6 - 9
Projects/Src/Setup.ScriptFunc.pas

@@ -317,23 +317,23 @@ var
     RegisterScriptFunc('BROWSEFORFOLDER', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       var S := Stack.GetString(PStart-2);
-      Stack.SetBool(PStart, BrowseForFolder(Stack.GetString(PStart-1), S, GetWizardFormHandle, Stack.GetBool(PStart-3)));
+      Stack.SetBool(PStart, BrowseForFolder(Stack.GetString(PStart-1), S, GetOwnerWndForMessageBox, Stack.GetBool(PStart-3)));
       Stack.SetString(PStart-2, S);
     end);
     RegisterScriptFunc('GETOPENFILENAME', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       var S := Stack.GetString(PStart-2);
-      Stack.SetBool(PStart, NewGetOpenFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetWizardFormHandle));
+      Stack.SetBool(PStart, NewGetOpenFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetOwnerWndForMessageBox));
       Stack.SetString(PStart-2, S);
     end);
     RegisterScriptFunc('GETOPENFILENAMEMULTI', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
-      Stack.SetBool(PStart, NewGetOpenFileNameMulti(Stack.GetString(PStart-1), TStrings(Stack.GetClass(PStart-2)), Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetWizardFormHandle));
+      Stack.SetBool(PStart, NewGetOpenFileNameMulti(Stack.GetString(PStart-1), TStrings(Stack.GetClass(PStart-2)), Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetOwnerWndForMessageBox));
     end);
     RegisterScriptFunc('GETSAVEFILENAME', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       var S := Stack.GetString(PStart-2);
-      Stack.SetBool(PStart, NewGetSaveFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetWizardFormHandle));
+      Stack.SetBool(PStart, NewGetSaveFileName(Stack.GetString(PStart-1), S, Stack.GetString(PStart-3), Stack.GetString(PStart-4), Stack.GetString(PStart-5), GetOwnerWndForMessageBox));
       Stack.SetString(PStart-2, S);
     end);
   end;
@@ -1175,10 +1175,6 @@ var
     begin
       Stack.SetBool(PStart, CodeRegisterExtraCloseApplicationsResource(Stack.GetBool(PStart-1), Stack.GetString(PStart-2)));
     end);
-    RegisterScriptFunc('GETMAINFORM', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
-    begin
-      Stack.SetClass(PStart, GetMainForm);
-    end);
     RegisterScriptFunc('GETWIZARDFORM', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       Stack.SetClass(PStart, GetWizardForm);
@@ -1591,8 +1587,9 @@ var
   begin
     RegisterScriptFunc('BRINGTOFRONTANDRESTORE', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
-      Application.BringToFront;
+      { Must be in this order to work around VCL bug }
       Application.Restore;
+      Application.BringToFront;
     end);
     RegisterScriptFunc('WizardDirValue', sfNoUninstall, procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin

+ 1 - 1
Projects/Src/Setup.SelectLanguageForm.pas

@@ -48,7 +48,7 @@ var
   I, J: Integer;
   LangEntry: PSetupLanguageEntry;
 begin
-  LangForm := TSelectLanguageForm.Create(Application);
+  Application.CreateForm(TSelectLanguageForm, LangForm);
   try
     for I := 0 to Entries[seLanguage].Count-1 do begin
       LangEntry := Entries[seLanguage][I];

+ 7 - 0
Projects/Src/Setup.SetupForm.pas

@@ -331,6 +331,13 @@ procedure TSetupForm.CenterInsideControl(const Ctl: TWinControl;
 var
   R: TRect;
 begin
+  const CtlForm = GetParentForm(Ctl);
+  if (CtlForm = nil) or not IsWindowVisible(CtlForm.Handle) or
+     IsIconic(CtlForm.Handle) then begin
+    Center;
+    Exit;
+  end;
+
   if not InsideClientArea then begin
     if GetWindowRect(Ctl.Handle, R) then
       CenterInsideRect(R);

+ 5 - 30
Projects/Src/Setup.Uninstall.pas

@@ -91,7 +91,7 @@ end;
 
 procedure InitializeUninstallProgressForm;
 begin
-  UninstallProgressForm := TUninstallProgressForm.Create(nil);
+  Application.CreateForm(TUninstallProgressForm, UninstallProgressForm);
   UninstallProgressForm.Initialize(Title, UninstLog.AppName, ufModernStyle in UninstLog.Flags);
   if CodeRunner <> nil then begin
     try
@@ -349,19 +349,9 @@ begin
   RequireAdmin := (ufAdminInstalled in Flags) or (ufPowerUserInstalled in Flags);
 
   if NeedToRespawnSelfElevated(RequireAdmin, False) then begin
-    { Hide the taskbar button }
-    SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
-      SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
-    try
-      RespawnSelfElevated(UninstExeFilename,
-        Format('/INITPROCWND=$%x ', [Application.Handle]) + GetCmdTail,
-        UninstallExitCode);
-    except
-      { Re-show the taskbar button and re-raise }
-      if not(ExceptObject is EAbort) then
-        ShowWindow(Application.Handle, SW_SHOW);
-      raise;
-    end;
+    RespawnSelfElevated(UninstExeFilename,
+      Format('/INITPROCWND=$%x ', [Application.Handle]) + GetCmdTail,
+      UninstallExitCode);
     Result := True;
   end;
 end;
@@ -402,11 +392,6 @@ begin
   Longint(OldWindowProc) := SetWindowLong(Wnd, GWL_WNDPROC,
     Longint(@FirstPhaseWindowProc));
   try
-    { Hide the application window so that we don't end up with two taskbar
-      buttons once the second phase starts }
-    SetWindowPos(Application.Handle, 0, 0, 0, 0, 0, SWP_NOSIZE or
-      SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE or SWP_HIDEWINDOW);
-
     { Execute the copy of itself ("second phase") }
     ProcessHandle := Exec(TempFile, Format('/SECONDPHASE="%s" /FIRSTPHASEWND=$%x ',
       [NewParamStr(0), Wnd]) + GetCmdTail);
@@ -485,9 +470,6 @@ var
   Res, RemovedAll, UninstallNeedsRestart: Boolean;
   StartTime: DWORD;
 begin
-  if VerySilent then
-    SetTaskbarButtonVisibility(False);
-
   RestartSystem := False;
   AllowUninstallerShutdown := True;
 
@@ -736,11 +718,6 @@ begin
       Log('Restarting Windows.');
       RestartInitiatedByThisProcess := True;
       if not RestartComputer then begin
-        { If another app denied the shutdown, we probably lost the foreground;
-          try to take it back. (Note: Application.BringToFront can't be used
-          because we have no visible forms, and MB_SETFOREGROUND doesn't make
-          the app's taskbar button blink.) }
-        SetForegroundWindow(Application.Handle);
         LoggedAppMessageBox(PChar(SetupMessages[msgErrorRestartingComputer]),
           PChar(SetupMessages[msgErrorTitle]), MB_OK or MB_ICONEXCLAMATION,
           True, IDOK);
@@ -758,9 +735,7 @@ var
 begin
   { Set default title; it's set again below after the messages are read }
   Application.Title := 'Uninstall';
-  { This is needed for D3+: Must force the application window visible since
-    we aren't displaying any forms }
-  ShowWindow(Application.Handle, SW_SHOW);
+  Application.MainFormOnTaskBar := True;
 
   try
     InitializeCommonVars;

+ 2 - 4
Projects/Src/Setup.WizardForm.dfm

@@ -1,8 +1,8 @@
 object WizardForm: TWizardForm
   Left = 191
   Top = 139
-  BorderIcons = [biSystemMenu]
-  BorderStyle = bsDialog
+  BorderIcons = [biSystemMenu, biMinimize]
+  BorderStyle = bsSingle
   Caption = 'WizardForm'
   ClientHeight = 360
   ClientWidth = 497
@@ -12,14 +12,12 @@ object WizardForm: TWizardForm
   Font.Height = -11
   Font.Name = 'MS Sans Serif'
   Font.Style = []
-  OldCreateOrder = True
   Scaled = False
   OnClose = FormClose
   OnResize = FormResize
   DesignSize = (
     497
     360)
-  PixelsPerInch = 96
   TextHeight = 13
   object FBevel: TBevel
     Left = 0

+ 31 - 55
Projects/Src/Setup.WizardForm.pas

@@ -211,8 +211,7 @@ type
     procedure UpdatePage(const PageID: Integer);
     procedure UpdateSelectTasksPage;
     procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND;
-  protected
-    procedure CreateParams(var Params: TCreateParams); override;
+    procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING;
   public
     { Public declarations }
     PrepareToInstallFailureMessage: String;
@@ -761,10 +760,9 @@ var
   SystemMenu: HMENU;
   P: String;
   I, DefaultSetupTypeIndex: Integer;
-  DfmDefault, IgnoreInitComponents: Boolean;
+  IgnoreInitComponents: Boolean;
   TypeEntry: PSetupTypeEntry;
   ComponentEntry: PSetupComponentEntry;
-  SaveClientWidth, SaveClientHeight: Integer;
 begin
   inherited;
 
@@ -793,34 +791,17 @@ begin
   WelcomeLabel1.Font.Style := [fsBold];
   PageNameLabel.Font.Style := [fsBold];
 
-  if shWindowVisible in SetupHeader.Options then
-    Caption := SetupMessages[msgSetupAppTitle]
-  else if shDisableWelcomePage in SetupHeader.Options then
+  if shDisableWelcomePage in SetupHeader.Options then
     Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppVerName)
   else
     Caption := FmtSetupMessage1(msgSetupWindowTitle, ExpandedAppName);
 
-  { Set BorderStyle and BorderIcons:
-    -WindowVisible + WizardResizable = sizeable
-    -not WindowVisible + WizardResizable = sizeable + minimize
-    -WindowVisible + not WizardResizable = dialog = .dfm default = do nothing
-    -not WindowVisible + not WizardResizable = single + minimize }
-  DfmDefault := (shWindowVisible in SetupHeader.Options) and not (shWizardResizable in SetupHeader.Options);
-  if not DfmDefault then begin
-    { Save ClientWidth/ClientHeight and restore them after changing BorderStyle. }
-    SaveClientWidth := ClientWidth;
-    SaveClientHeight := ClientHeight;
-    if not(shWindowVisible in SetupHeader.Options) then
-      BorderIcons := BorderIcons + [biMinimize];
-    if not(shWizardResizable in SetupHeader.Options) then
-      BorderStyle := bsSingle
-    else
-      BorderStyle := bsSizeable;
+  if shWizardResizable in SetupHeader.Options then begin
+    const SaveClientWidth = ClientWidth;
+    const SaveClientHeight = ClientHeight;
+    BorderStyle := bsSizeable;
     ClientWidth := SaveClientWidth;
     ClientHeight := SaveClientHeight;
-  end;
-
-  if shWizardResizable in SetupHeader.Options then begin
     EnableAnchorOuterPagesOnResize := True;
     { Do not allow user to resize it smaller than 100% nor larger than 150%. }
     Constraints.MinHeight := Height;
@@ -1347,14 +1328,6 @@ begin
   inherited;
 end;
 
-procedure TWizardForm.CreateParams(var Params: TCreateParams);
-begin
-  inherited;
-  { Ensure the form is *always* on top of MainForm by making MainForm
-    the "parent" of the form. }
-  Params.WndParent := MainForm.Handle;
-end;
-
 function TWizardForm.PageIndexFromID(const ID: Integer): Integer;
 { Given a page ID, returns the index of the page in FPageList. An exception is
   raised if a page with the specified ID is not found. }
@@ -1865,10 +1838,8 @@ begin
     BackButton.Visible := False;
     NextButton.Visible := False;
     CancelButton.Enabled := False;
-    if InstallMode = imSilent then begin
-      SetActiveWindow(Application.Handle);  { ensure taskbar button is selected }
-      WizardForm.Show;
-    end;
+    if InstallMode = imSilent then
+      WizardForm.Visible := True;
     WizardForm.Update;
     try
       DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages := True;
@@ -1879,7 +1850,8 @@ begin
       DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages := False;
       UpdateCurPageButtonState;
     end;
-    Application.BringToFront;
+    if WindowState <> wsMinimized then  { VCL bug workaround }
+      Application.BringToFront;
   end;
   if Result <> '' then begin
     if PrepareToInstallNeedsRestart then
@@ -2559,10 +2531,8 @@ begin
               SetCurPage(wpPreparing); { controls are already hidden by PrepareToInstall }
               BackButton.Visible := False;
               NextButton.Visible := False;
-              if InstallMode = imSilent then begin
-                SetActiveWindow(Application.Handle);  { ensure taskbar button is selected }
-                WizardForm.Show;
-              end;
+              if InstallMode = imSilent then
+                WizardForm.Visible := True;
               try
                 WizardForm.Update;
                 RmFoundApplications := QueryRestartManager(WizardComponents, WizardTasks) <> '';
@@ -2709,18 +2679,28 @@ end;
 
 procedure TWizardForm.WMSysCommand(var Message: TWMSysCommand);
 begin
-  if Message.CmdType and $FFF0 = SC_MINIMIZE then
-    { A minimize button is shown on the wizard form when (shWindowVisible in
-      SetupHeader.Options). When it is clicked we want to minimize the whole
-      application. }
-    Application.Minimize
-  else
   if Message.CmdType = 9999 then
     MainForm.ShowAboutBox
   else
     inherited;
 end;
 
+procedure TWizardForm.WMWindowPosChanging(var Message: TWMWindowPosChanging);
+begin
+  { Work around a VCL issue (Delphi 11.3) when MainFormOnTaskBar=True:
+    If Application.Restore is called while the main form is hidden
+    (Visible=False), the window can become visible because of the SW_RESTORE
+    command it uses, which both unminimizes and shows a window. Reproducer:
+      Application.Minimize;
+      Hide;
+      Application.Restore;
+    This blocks any attempt to show the window while Visible=False.
+    (SW_RESTORE will still unminimize the window; it just cannot show it.) }
+  inherited;
+  if not Visible then
+    Message.WindowPos.flags := Message.WindowPos.flags and not SWP_SHOWWINDOW;
+end;
+
 procedure TWizardForm.LicenseAcceptedRadioClick(Sender: TObject);
 begin
   if CurPageID = wpLicense then
@@ -3040,14 +3020,10 @@ begin
         { After installation, we can't abort since e.g. a restart might be
           needed. Instead, to avoid getting stuck in a loop, show the wizard
           (even though this is a silent install) and let the user deal with the
-          problem on their own.
-          The taskbar button will be hidden at this point on very silent
-          installs (see SetupInstallMode); re-show it. }
+          problem on their own. }
         Log('Failed to proceed to next wizard page; showing wizard.');
-        SetTaskbarButtonVisibility(True);
+        WizardForm.Visible := True;
         Application.Restore;
-        SetActiveWindow(Application.Handle);  { ensure taskbar button is selected }
-        WizardForm.Show;
         Break;
       end;
     end;

+ 33 - 7
Projects/Src/Shared.CommonFunc.Vcl.pas

@@ -54,6 +54,7 @@ procedure SetMessageBoxRightToLeft(const ARightToLeft: Boolean);
 function GetMessageBoxRightToLeft: Boolean;
 procedure SetMessageBoxCallbackFunc(const AFunc: TMsgBoxCallbackFunc; const AParam: LongInt);
 procedure TriggerMessageBoxCallbackFunc(const Flags: LongInt; const After: Boolean);
+function GetOwnerWndForMessageBox: HWND;
 
 implementation
 
@@ -207,11 +208,42 @@ begin
   end;
 end;
 
+function GetOwnerWndForMessageBox: HWND;
+{ Returns window handle that Application.MessageBox, if called immediately
+  after this function, would use as the owner window for the message box.
+  Exception: If the window that would be returned is not shown on the taskbar,
+  or is a minimized Application.Handle window, then 0 is returned instead.
+  See comments in AppMessageBox. }
+begin
+  { This is what Application.MessageBox does (Delphi 11.3) }
+  Result := Application.ActiveFormHandle;
+  if Result = 0 then  { shouldn't be possible, but they have this check }
+    Result := Application.Handle;
+
+  { Now our override }
+  if ((Result = Application.Handle) and IsIconic(Result)) or
+     (GetWindowLong(Result, GWL_STYLE) and WS_VISIBLE = 0) or
+     (GetWindowLong(Result, GWL_EXSTYLE) and WS_EX_TOOLWINDOW <> 0) then
+    Result := 0;
+end;
+
 function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer;
 var
   ActiveWindow: HWND;
   WindowList: Pointer;
 begin
+  { Always restore the app first if it's minimized. This makes sense from a
+    usability perspective (e.g., it may be unclear which app generated the
+    message box if it's shown by itself), but it's also a VCL bug mitigation
+    (seen on Delphi 11.3):
+    Without this, when Application.MainFormOnTaskBar=True, showing a window
+    like a message box causes a WM_ACTIVATEAPP message to be sent to
+    Application.Handle, and the VCL strangely responds by setting FAppIconic
+    to False -- even though the main form is still iconic (minimized). If we
+    later try to call Application.Restore, nothing happens because it sees
+    FAppIconic=False. }
+  Application.Restore;
+
   { Always try to bring the message box to the foreground. Task dialogs appear
     to do that by default.
     Without this, if the main form is minimized and then closed via the
@@ -266,13 +298,7 @@ begin
       (This problem doesn't occur when Application.MainFormOnTaskBar=True
       because the main form retains its WS_VISIBLE style while minimized.)
     }
-    var ActWnd := Application.ActiveFormHandle;
-    if ActWnd = 0 then  { shouldn't be possible, but they have this check }
-      ActWnd := Application.Handle;
-    if (ActWnd = Application.Handle) and
-       (IsIconic(Application.Handle) or
-        (GetWindowLong(Application.Handle, GWL_STYLE) and WS_VISIBLE = 0) or
-        (GetWindowLong(Application.Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW <> 0)) then begin
+    if GetOwnerWndForMessageBox = 0 then begin
       ActiveWindow := GetActiveWindow;
       WindowList := DisableTaskWindows(0);
       try

+ 0 - 2
Projects/Src/Shared.ScriptFunc.pas

@@ -400,8 +400,6 @@ initialization
     'function CustomMessage(const MsgName: String): String;',
     'function RmSessionStarted: Boolean;',
     'function RegisterExtraCloseApplicationsResource(const DisableFsRedir: Boolean; const AFilename: String): Boolean;',
-    { Actually access MainForm.pas }
-    'function GetMainForm: TMainForm;',
     { Actually access WizardForm.pas }
     'function GetWizardForm: TWizardForm;',
     'function WizardIsComponentSelected(const Components: String): Boolean;',

+ 3 - 5
Projects/Src/Shared.Struct.pas

@@ -33,7 +33,7 @@ const
     this file it's recommended you change SetupID. Any change will do (like
     changing the letters or numbers), as long as your format is
     unrecognizable by the standard Inno Setup. }
-  SetupID: TSetupID = 'Inno Setup Setup Data (6.4.0)';
+  SetupID: TSetupID = 'Inno Setup Setup Data (6.4.0.1)';
   UninstallLogID: array[Boolean] of TUninstallLogID =
     ('Inno Setup Uninstall Log (b)', 'Inno Setup Uninstall Log (b) 64-bit');
   MessagesHdrID: TMessagesHdrID = 'Inno Setup Messages (6.4.0) (u)';
@@ -51,10 +51,9 @@ type
   end;
   TSetupHeaderOption = (shDisableStartupPrompt, shCreateAppDir,
     shAllowNoIcons, shAlwaysRestart, shAlwaysUsePersonalGroup,
-    shWindowVisible, shWindowShowCaption, shWindowResizable,
-    shWindowStartMaximized, shEnableDirDoesntExistWarning,
+    shEnableDirDoesntExistWarning,
     shPassword, shAllowRootDirectory, shDisableFinishedPage, shUsePreviousAppDir,
-    shBackColorHorizontal, shUsePreviousGroup, shUpdateUninstallLogAppName,
+    shUsePreviousGroup, shUpdateUninstallLogAppName,
     shUsePreviousSetupType, shDisableReadyMemo, shAlwaysShowComponentsList,
     shFlatComponentsList, shShowComponentSizes, shUsePreviousTasks,
     shDisableReadyPage, shAlwaysShowDirOnReadyPage, shAlwaysShowGroupOnReadyPage,
@@ -106,7 +105,6 @@ type
       NumRegistryEntries, NumInstallDeleteEntries, NumUninstallDeleteEntries,
       NumRunEntries, NumUninstallRunEntries: Integer;
     MinVersion, OnlyBelowVersion: TSetupVersionData;
-    BackColor, BackColor2: Longint;
     WizardStyle: TSetupWizardStyle;
     WizardSizePercentX, WizardSizePercentY: Integer;
     WizardImageAlphaFormat: (afIgnored, afDefined, afPremultiplied); // Must be same as Graphics.TAlphaFormat

+ 4 - 10
Projects/Src/Shared.TaskDialogFunc.pas

@@ -49,15 +49,8 @@ begin
     Config.cbSize := SizeOf(Config);
     if RightToLeft then
       Config.dwFlags := Config.dwFlags or TDF_RTL_LAYOUT;
-    { If the application window isn't currently visible, show the task dialog
-      with no owner window so it'll get a taskbar button } 
     Config.hInstance := HInstance;
-    if IsIconic(Application.Handle) or
-       (GetWindowLong(Application.Handle, GWL_STYLE) and WS_VISIBLE = 0) or
-       (GetWindowLong(Application.Handle, GWL_EXSTYLE) and WS_EX_TOOLWINDOW <> 0) then
-      Config.hWndParent := 0
-    else
-      Config.hwndParent := hWnd;
+    Config.hwndParent := hWnd;
     Config.dwCommonButtons := CommonButtons;
     Config.pszWindowTitle := Caption;
     Config.pszMainIcon := Icon;
@@ -85,7 +78,7 @@ begin
       end;
       TriggerMessageBoxCallbackFunc(TriggerMessageBoxCallbackFuncFlags, False);
       ActiveWindow := GetActiveWindow;
-      WindowList := DisableTaskWindows(0);
+      WindowList := DisableTaskWindows(Config.hwndParent);
       try
         Result := TaskDialogIndirectFunc(Config, @ModalResult, nil, pfVerificationFlagChecked) = S_OK;
       finally
@@ -116,6 +109,7 @@ var
   NButtonLabelsAvailable: Integer;
   ButtonIDs: array of Integer;
 begin
+  Application.Restore; { See comments in AppMessageBox }
   if Icon <> '' then
     IconP := PChar(Icon)
   else begin
@@ -177,7 +171,7 @@ begin
   end;
   if Length(ButtonIDs) <> NButtonLabelsAvailable then
     DoInternalError('TaskDialogMsgBox: Invalid ButtonLabels');
-  if not DoTaskDialog(Application.Handle, PChar(Instruction), PChar(Text),
+  if not DoTaskDialog(GetOwnerWndForMessageBox, PChar(Instruction), PChar(Text),
            GetMessageBoxCaption(PChar(Caption), Typ), IconP, TDCommonButtons, ButtonLabels, ButtonIDs, ShieldButton,
            GetMessageBoxRightToLeft, IfThen(Typ in [mbError, mbCriticalError], MB_ICONSTOP, 0), Result, PChar(VerificationText), pfVerificationFlagChecked) then //note that MB_ICONEXCLAMATION (used by mbError) includes MB_ICONSTOP (used by mbCriticalError)
     Result := 0;

+ 1 - 0
whatsnew.htm

@@ -91,6 +91,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
   <li>Updated the encryption algorithm and key derivation function used by Inno Setup to XChaCha20 and PBKDF2-HMAC-SHA256 respectively, increasing security. This code is built-in: the separate ISCrypt.dll "encryption module" is no longer used and will be automatically deleted when you update.</li>
   <li>Added <tt>[Setup]</tt> section directive <tt>EncryptionKeyDerivation</tt> to change the number of PBKDF2-HMAC-SHA256 iterations to use from the default of 200000 to another value.</li>
   <li>Replaced all remaining use of MD5 and SHA-1 hashes with SHA-256 hashes, without removing the MD5 and SHA-1 Pascal Scripting and ISPP support functions.</li>
+  <li>At long last, Setup's wizard window now shows a thumbnail image on its taskbar button, and animates correctly when minimized and restored. As part of this work, support for the long-deprecated <tt>[Setup]</tt> section directive <tt>WindowVisible</tt>, which was used to enable a 1990s-style blue gradient background behind the wizard window, has been dropped.</li>
   <li>The aspect ratio of Setup's large and small wizard images (as specified by <tt>WizardImageFile</tt> and <tt>WizardSmallImageFile</tt>) is now maintained when the window is scaled. Previously, depending on the font and font size used, they could have appeared horizontally stretched or squished.</li>
   <li>The New Script Wizard now sets <tt>UninstallDisplayIcon</tt> when an .exe is chosen as the main executable file.</li>
   <li>Merged the Inno Setup Preprocessor documentation into the main documentation instead of being separate.</li>