From 1f9aa4125cf6b6e1b667c3f61213aae1e7eb8628 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sat, 14 Dec 2024 00:02:37 -0600 Subject: [PATCH 01/19] Begin dismantling TMainForm and WindowVisible=yes. Enough is enough. Making WizardForm the main form so that Application.MainFormOnTaskBar=True can be set is long overdue. --- Projects/Src/Compiler.SetupCompiler.pas | 41 +++++-------------------- 1 file changed, 8 insertions(+), 33 deletions(-) diff --git a/Projects/Src/Compiler.SetupCompiler.pas b/Projects/Src/Compiler.SetupCompiler.pas index d8f0b586f..1f67e1e43 100644 --- a/Projects/Src/Compiler.SetupCompiler.pas +++ b/Projects/Src/Compiler.SetupCompiler.pas @@ -2579,30 +2579,11 @@ procedure TSetupCompiler.EnumSetupProc(const Line: PChar; const Ext: Integer); 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 @@ procedure TSetupCompiler.EnumSetupProc(const Line: PChar; const Ext: Integer); 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 From 9d52a240405ebbaa04a06e6cf3b0450edee47c2e Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sat, 14 Dec 2024 04:44:08 -0600 Subject: [PATCH 02/19] Setup: De-form TMainForm and set MainFormOnTaskBar=True. Mostly done, I think. Still need to actually remove shWindowVisible etc. Still some Application.Handle references that need to be cleaned out. Still need to update help. TMainForm still exists, but is no longer a form. Good enough for now. With Application.MainFormOnTaskBar=True, we now have a working taskbar thumbnail and proper minimize/restore animations. Finally. --- Projects/Setup.dpr | 41 +-- Projects/Src/Compiler.ScriptClasses.pas | 10 - Projects/Src/Setup.MainForm.pas | 301 ++-------------------- Projects/Src/Setup.MainFunc.pas | 43 ---- Projects/Src/Setup.ScriptClasses.pas | 10 - Projects/Src/Setup.ScriptFunc.pas | 4 - Projects/Src/Setup.SelectLanguageForm.pas | 2 +- Projects/Src/Setup.Uninstall.pas | 9 +- Projects/Src/Setup.WizardForm.pas | 20 +- Projects/Src/Shared.ScriptFunc.pas | 2 - 10 files changed, 28 insertions(+), 414 deletions(-) diff --git a/Projects/Setup.dpr b/Projects/Setup.dpr index 5f44135f8..f96559267 100644 --- a/Projects/Setup.dpr +++ b/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,12 +254,6 @@ 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; @@ -299,17 +270,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; diff --git a/Projects/Src/Compiler.ScriptClasses.pas b/Projects/Src/Compiler.ScriptClasses.pas index f5895a89c..1fca3380a 100644 --- a/Projects/Src/Compiler.ScriptClasses.pas +++ b/Projects/Src/Compiler.ScriptClasses.pas @@ -311,14 +311,6 @@ procedure RegisterSetupForm_C(Cl: TPSPascalCompiler); 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 @@ procedure ScriptClassesLibraryRegister_C(Cl: TPSPascalCompiler); RegisterUIStateForm_C(Cl); RegisterSetupForm_C(Cl); - RegisterMainForm_C(Cl); RegisterWizardForm_C(Cl); RegisterUninstallProgressForm_C(Cl); @@ -694,7 +685,6 @@ procedure ScriptClassesLibraryRegister_C(Cl: TPSPascalCompiler); RegisterHandCursor_C(Cl); AddImportedClassVariable(Cl, 'WizardForm', 'TWizardForm'); - AddImportedClassVariable(Cl, 'MainForm', 'TMainForm'); AddImportedClassVariable(Cl, 'UninstallProgressForm', 'TUninstallProgressForm'); end; diff --git a/Projects/Src/Setup.MainForm.pas b/Projects/Src/Setup.MainForm.pas index af8137551..f3133f3e9 100644 --- a/Projects/Src/Setup.MainForm.pas +++ b/Projects/Src/Setup.MainForm.pas @@ -13,28 +13,16 @@ 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; @@ -56,176 +44,12 @@ implementation 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 +108,6 @@ procedure TMainForm.SetStep(const AStep: TSetupStep; const HandleExceptions: Boo procedure TMainForm.InitializeWizard; begin - WizardForm := TWizardForm.Create(Application); if CodeRunner <> nil then begin try CodeRunner.RunProcedures('InitializeWizard', [''], False); @@ -293,11 +116,10 @@ procedure TMainForm.InitializeWizard; 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; end else @@ -340,6 +162,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 +188,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.Show; end; end; DebugNotifyEntry(seRun, I); @@ -383,10 +206,8 @@ function TMainForm.Install: Boolean; end; end; finally - if HideWizard then begin - HideWizard := False; - UpdateWizardFormVisibility; - end; + if WizardWasHidden then + WizardForm.Show; WindowDisabler.Free; if CheckIfRestartNeeded then begin ChecksumAfter := MakePendingFileRenameOperationsChecksum; @@ -453,11 +274,8 @@ function TMainForm.Install: Boolean; SaveInf(InitSaveInf); Application.Restore; - Update; - if InstallMode = imSilent then begin - SetActiveWindow(Application.Handle); { ensure taskbar button is selected } + if InstallMode = imSilent then WizardForm.Show; - end; WizardForm.Update; SetStep(ssInstall, False); @@ -514,10 +332,8 @@ function TMainForm.Install: Boolean; end; end; - if InstallMode = imNormal then begin + if InstallMode = imNormal then Application.Restore; - Update; - end; Result := True; except @@ -653,7 +469,7 @@ procedure TMainForm.Finish(const FromPreparingPage: Boolean); TerminateApp; end; -procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); +procedure TMainForm.Close; function ConfirmCancel(const DefaultConfirm: Boolean): Boolean; var @@ -666,9 +482,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,84 +502,6 @@ procedure TMainForm.FormCloseQuery(Sender: TObject; var CanClose: Boolean); 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 @@ -786,7 +521,7 @@ procedure TMainForm.RestoreApp; 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); + //UpdateWizardFormVisibility(True); Application.Restore; end; Application.BringToFront; diff --git a/Projects/Src/Setup.MainFunc.pas b/Projects/Src/Setup.MainFunc.pas index 8aa3ce64e..bbc4380ce 100644 --- a/Projects/Src/Setup.MainFunc.pas +++ b/Projects/Src/Setup.MainFunc.pas @@ -153,7 +153,6 @@ interface 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 @@ function ExpandIndividualConst(Cnst: String; 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 @@ procedure ActivateDefaultLanguage; 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; @@ -2711,14 +2676,6 @@ procedure InitializeSetup; 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; diff --git a/Projects/Src/Setup.ScriptClasses.pas b/Projects/Src/Setup.ScriptClasses.pas index 187a85ff1..2421ee1af 100644 --- a/Projects/Src/Setup.ScriptClasses.pas +++ b/Projects/Src/Setup.ScriptClasses.pas @@ -202,14 +202,6 @@ procedure RegisterSetupForm_R(Cl: TPSRuntimeClassImporter); 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 @@ function ScriptClassesLibraryRegister_R(ScriptInterpreter: TPSExec): TPSRuntimeC RegisterUIStateForm_R(Cl); RegisterSetupForm_R(Cl); - RegisterMainForm_R(Cl); RegisterWizardForm_R(Cl); RegisterUninstallProgressForm_R(Cl); @@ -474,7 +465,6 @@ function ScriptClassesLibraryRegister_R(ScriptInterpreter: TPSExec): TPSRuntimeC 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; diff --git a/Projects/Src/Setup.ScriptFunc.pas b/Projects/Src/Setup.ScriptFunc.pas index 2b668af14..5c862679b 100644 --- a/Projects/Src/Setup.ScriptFunc.pas +++ b/Projects/Src/Setup.ScriptFunc.pas @@ -1175,10 +1175,6 @@ procedure ScriptFuncLibraryRegister_R(ScriptInterpreter: TPSExec); 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); diff --git a/Projects/Src/Setup.SelectLanguageForm.pas b/Projects/Src/Setup.SelectLanguageForm.pas index 1acdc22b2..e3e4a8365 100644 --- a/Projects/Src/Setup.SelectLanguageForm.pas +++ b/Projects/Src/Setup.SelectLanguageForm.pas @@ -48,7 +48,7 @@ function AskForLanguage: Boolean; 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]; diff --git a/Projects/Src/Setup.Uninstall.pas b/Projects/Src/Setup.Uninstall.pas index 8897367df..26bdb54e6 100644 --- a/Projects/Src/Setup.Uninstall.pas +++ b/Projects/Src/Setup.Uninstall.pas @@ -91,7 +91,7 @@ function TExtUninstallLog.ShouldRemoveSharedFile(const Filename: String): Boolea 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 @@ -485,9 +485,6 @@ procedure RunSecondPhase; Res, RemovedAll, UninstallNeedsRestart: Boolean; StartTime: DWORD; begin - if VerySilent then - SetTaskbarButtonVisibility(False); - RestartSystem := False; AllowUninstallerShutdown := True; @@ -758,9 +755,7 @@ procedure RunUninstaller; 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; diff --git a/Projects/Src/Setup.WizardForm.pas b/Projects/Src/Setup.WizardForm.pas index ed10c37c7..bb74a3a75 100644 --- a/Projects/Src/Setup.WizardForm.pas +++ b/Projects/Src/Setup.WizardForm.pas @@ -211,8 +211,6 @@ TWizardForm = class(TSetupForm) procedure UpdatePage(const PageID: Integer); procedure UpdateSelectTasksPage; procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND; - protected - procedure CreateParams(var Params: TCreateParams); override; public { Public declarations } PrepareToInstallFailureMessage: String; @@ -1347,14 +1345,6 @@ destructor TWizardForm.Destroy; 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 +1855,8 @@ function TWizardForm.PrepareToInstall(const WizardComponents, WizardTasks: TStri BackButton.Visible := False; NextButton.Visible := False; CancelButton.Enabled := False; - if InstallMode = imSilent then begin - SetActiveWindow(Application.Handle); { ensure taskbar button is selected } + if InstallMode = imSilent then WizardForm.Show; - end; WizardForm.Update; try DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages := True; @@ -2559,10 +2547,8 @@ procedure TWizardForm.NextButtonClick(Sender: TObject); 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 } + if InstallMode = imSilent then WizardForm.Show; - end; try WizardForm.Update; RmFoundApplications := QueryRestartManager(WizardComponents, WizardTasks) <> ''; @@ -3044,9 +3030,7 @@ procedure TWizardForm.ClickThroughPages; The taskbar button will be hidden at this point on very silent installs (see SetupInstallMode); re-show it. } Log('Failed to proceed to next wizard page; showing wizard.'); - SetTaskbarButtonVisibility(True); Application.Restore; - SetActiveWindow(Application.Handle); { ensure taskbar button is selected } WizardForm.Show; Break; end; diff --git a/Projects/Src/Shared.ScriptFunc.pas b/Projects/Src/Shared.ScriptFunc.pas index 506dcaee3..359bc9cc1 100644 --- a/Projects/Src/Shared.ScriptFunc.pas +++ b/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;', From c29c12eeb19072c7e3d8cf786f66ecfa56c855d1 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 15 Dec 2024 01:02:09 -0600 Subject: [PATCH 03/19] Finish updating Setup.WizardForm. --- Projects/Src/Setup.WizardForm.dfm | 6 ++---- Projects/Src/Setup.WizardForm.pas | 36 ++++++------------------------- 2 files changed, 8 insertions(+), 34 deletions(-) diff --git a/Projects/Src/Setup.WizardForm.dfm b/Projects/Src/Setup.WizardForm.dfm index b9b8a4acb..4cccae5ad 100644 --- a/Projects/Src/Setup.WizardForm.dfm +++ b/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 diff --git a/Projects/Src/Setup.WizardForm.pas b/Projects/Src/Setup.WizardForm.pas index bb74a3a75..f713bf346 100644 --- a/Projects/Src/Setup.WizardForm.pas +++ b/Projects/Src/Setup.WizardForm.pas @@ -759,10 +759,9 @@ constructor TWizardForm.Create(AOwner: TComponent); SystemMenu: HMENU; P: String; I, DefaultSetupTypeIndex: Integer; - DfmDefault, IgnoreInitComponents: Boolean; + IgnoreInitComponents: Boolean; TypeEntry: PSetupTypeEntry; ComponentEntry: PSetupComponentEntry; - SaveClientWidth, SaveClientHeight: Integer; begin inherited; @@ -791,34 +790,17 @@ constructor TWizardForm.Create(AOwner: TComponent); 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; @@ -2695,12 +2677,6 @@ procedure TWizardForm.NoIconsCheckClick(Sender: TObject); 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 From 56828462f14454d74068c7b9774fabeddfb34180 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 15 Dec 2024 01:53:59 -0600 Subject: [PATCH 04/19] Finish updating compiler, Struct. --- Projects/Src/Compiler.SetupCompiler.pas | 12 +++--------- Projects/Src/Shared.Struct.pas | 6 ++---- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/Projects/Src/Compiler.SetupCompiler.pas b/Projects/Src/Compiler.SetupCompiler.pas index 1f67e1e43..fded69d51 100644 --- a/Projects/Src/Compiler.SetupCompiler.pas +++ b/Projects/Src/Compiler.SetupCompiler.pas @@ -123,7 +123,7 @@ TSetupCompiler = class 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', @@ -7360,7 +7360,6 @@ procedure TSetupCompiler.Compile; SetupHeader.MinVersion.NTVersion := $06010000; SetupHeader.MinVersion.NTServicePack := $100; SetupHeader.Options := [shDisableStartupPrompt, shCreateAppDir, - shWindowStartMaximized, shWindowShowCaption, shWindowResizable, shUsePreviousAppDir, shUsePreviousGroup, shUsePreviousSetupType, shAlwaysShowComponentsList, shFlatComponentsList, shShowComponentSizes, shUsePreviousTasks, shUpdateUninstallLogAppName, @@ -7373,15 +7372,12 @@ procedure TSetupCompiler.Compile; 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; @@ -7480,8 +7476,6 @@ procedure TSetupCompiler.Compile; 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; diff --git a/Projects/Src/Shared.Struct.pas b/Projects/Src/Shared.Struct.pas index d10232f24..4583daa41 100644 --- a/Projects/Src/Shared.Struct.pas +++ b/Projects/Src/Shared.Struct.pas @@ -33,7 +33,7 @@ interface 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,8 +51,7 @@ interface end; TSetupHeaderOption = (shDisableStartupPrompt, shCreateAppDir, shAllowNoIcons, shAlwaysRestart, shAlwaysUsePersonalGroup, - shWindowVisible, shWindowShowCaption, shWindowResizable, - shWindowStartMaximized, shEnableDirDoesntExistWarning, + shEnableDirDoesntExistWarning, shPassword, shAllowRootDirectory, shDisableFinishedPage, shUsePreviousAppDir, shBackColorHorizontal, shUsePreviousGroup, shUpdateUninstallLogAppName, shUsePreviousSetupType, shDisableReadyMemo, shAlwaysShowComponentsList, @@ -106,7 +105,6 @@ TSetupEncryptionNonce = record 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 From aef9408ff2d56e22b9fc390d2ebd7d229fe4d2de Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 15 Dec 2024 03:47:17 -0600 Subject: [PATCH 05/19] Clean out remaining showing/hiding of app window, and fix taskbar progress. The ShutdownBlockReason calls still pass Application.Handle for the window handle. The docs don't say what the handle is used for. Maybe to supply an icon to display with the specified text? --- Components/TaskbarProgressFunc.pas | 10 ++++++---- Projects/Src/Setup.MainFunc.pas | 17 +---------------- Projects/Src/Setup.RegSvr.pas | 6 +----- Projects/Src/Setup.Uninstall.pas | 26 +++----------------------- 4 files changed, 11 insertions(+), 48 deletions(-) diff --git a/Components/TaskbarProgressFunc.pas b/Components/TaskbarProgressFunc.pas index cb988d79f..3de90c54a 100644 --- a/Components/TaskbarProgressFunc.pas +++ b/Components/TaskbarProgressFunc.pas @@ -48,14 +48,16 @@ procedure SetAppTaskbarProgressState(const State: TTaskbarProgressState); 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. diff --git a/Projects/Src/Setup.MainFunc.pas b/Projects/Src/Setup.MainFunc.pas index bbc4380ce..c30616ada 100644 --- a/Projects/Src/Setup.MainFunc.pas +++ b/Projects/Src/Setup.MainFunc.pas @@ -2389,14 +2389,6 @@ procedure RestartComputerFromThisProcess; 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; @@ -2415,9 +2407,6 @@ procedure RespawnSetupElevated(const AParams: String); 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; @@ -2438,11 +2427,8 @@ procedure RespawnSetupElevated(const AParams: String); { 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); @@ -2461,7 +2447,6 @@ procedure RespawnSetupElevated(const AParams: String); 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; diff --git a/Projects/Src/Setup.RegSvr.pas b/Projects/Src/Setup.RegSvr.pas index ed1559057..a2e41f491 100644 --- a/Projects/Src/Setup.RegSvr.pas +++ b/Projects/Src/Setup.RegSvr.pas @@ -119,9 +119,7 @@ procedure RunRegSvr; { 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 @@ procedure RunRegSvr; 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 @@ procedure RunRegSvr; 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'); diff --git a/Projects/Src/Setup.Uninstall.pas b/Projects/Src/Setup.Uninstall.pas index 26bdb54e6..a01ad0462 100644 --- a/Projects/Src/Setup.Uninstall.pas +++ b/Projects/Src/Setup.Uninstall.pas @@ -349,19 +349,9 @@ function RespawnFirstPhaseIfNeeded: Boolean; 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 @@ procedure RunFirstPhase; 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); @@ -733,11 +718,6 @@ procedure RunSecondPhase; 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); From ee956ccbb6497b46a96efd20e64d1ef7cd5ce043 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Mon, 16 Dec 2024 02:00:00 -0600 Subject: [PATCH 06/19] Unminimize before displaying message boxes and task dialogs. Now that MainFormOnTaskBar=True, Application.Restore doesn't steal the foreground anymore. --- Projects/Src/Setup.MainForm.pas | 26 -------------------------- Projects/Src/Setup.NewDiskForm.pas | 3 ++- Projects/Src/Shared.CommonFunc.Vcl.pas | 12 ++++++++++++ Projects/Src/Shared.TaskDialogFunc.pas | 1 + 4 files changed, 15 insertions(+), 27 deletions(-) diff --git a/Projects/Src/Setup.MainForm.pas b/Projects/Src/Setup.MainForm.pas index f3133f3e9..79e7098c2 100644 --- a/Projects/Src/Setup.MainForm.pas +++ b/Projects/Src/Setup.MainForm.pas @@ -26,7 +26,6 @@ TMainForm = class(TComponent) 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); @@ -502,31 +501,6 @@ procedure TMainForm.Close; end; 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 } diff --git a/Projects/Src/Setup.NewDiskForm.pas b/Projects/Src/Setup.NewDiskForm.pas index a979af0bc..79c473d8f 100644 --- a/Projects/Src/Setup.NewDiskForm.pas +++ b/Projects/Src/Setup.NewDiskForm.pas @@ -48,7 +48,8 @@ implementation 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 diff --git a/Projects/Src/Shared.CommonFunc.Vcl.pas b/Projects/Src/Shared.CommonFunc.Vcl.pas index e0f7a65d8..c01a41a95 100644 --- a/Projects/Src/Shared.CommonFunc.Vcl.pas +++ b/Projects/Src/Shared.CommonFunc.Vcl.pas @@ -212,6 +212,18 @@ function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer; 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 diff --git a/Projects/Src/Shared.TaskDialogFunc.pas b/Projects/Src/Shared.TaskDialogFunc.pas index d4cf1b2e3..dd2cd1221 100644 --- a/Projects/Src/Shared.TaskDialogFunc.pas +++ b/Projects/Src/Shared.TaskDialogFunc.pas @@ -116,6 +116,7 @@ function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const NButtonLabelsAvailable: Integer; ButtonIDs: array of Integer; begin + Application.Restore; { See comments in AppMessageBox } if Icon <> '' then IconP := PChar(Icon) else begin From 0a0d827d347c4feef86c284eff40e197ba4840a8 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Wed, 18 Dec 2024 01:21:57 -0600 Subject: [PATCH 07/19] Show message box with no owner when would-be owner form is hidden. Needed when AppMessageBox is called after WizardForm.Hide. --- Projects/Src/Shared.CommonFunc.Vcl.pas | 28 +++++++++++++++++++------- 1 file changed, 21 insertions(+), 7 deletions(-) diff --git a/Projects/Src/Shared.CommonFunc.Vcl.pas b/Projects/Src/Shared.CommonFunc.Vcl.pas index c01a41a95..1f3679d96 100644 --- a/Projects/Src/Shared.CommonFunc.Vcl.pas +++ b/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,6 +208,25 @@ procedure TriggerMessageBoxCallbackFunc(const Flags: LongInt; const After: Boole 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; @@ -278,13 +298,7 @@ function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer; (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 From f9d5475bdb9be11c0f7dd1e85d1fcef60751c2c6 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Wed, 18 Dec 2024 01:45:54 -0600 Subject: [PATCH 08/19] Use correct owner on task dialogs. --- Projects/Src/Shared.TaskDialogFunc.pas | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/Projects/Src/Shared.TaskDialogFunc.pas b/Projects/Src/Shared.TaskDialogFunc.pas index dd2cd1221..f22c4b323 100644 --- a/Projects/Src/Shared.TaskDialogFunc.pas +++ b/Projects/Src/Shared.TaskDialogFunc.pas @@ -49,15 +49,8 @@ function DoTaskDialog(const hWnd: HWND; const Instruction, Text, Caption, Icon: 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 @@ function DoTaskDialog(const hWnd: HWND; const Instruction, Text, Caption, Icon: end; TriggerMessageBoxCallbackFunc(TriggerMessageBoxCallbackFuncFlags, False); ActiveWindow := GetActiveWindow; - WindowList := DisableTaskWindows(0); + WindowList := DisableTaskWindows(Config.hwndParent); try Result := TaskDialogIndirectFunc(Config, @ModalResult, nil, pfVerificationFlagChecked) = S_OK; finally @@ -178,7 +171,7 @@ function TaskDialogMsgBox(const Icon, Instruction, Text, Caption: String; const 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; From f6f2f173816515f8e171675f60cd800fa0aa28db Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Wed, 18 Dec 2024 02:20:42 -0600 Subject: [PATCH 09/19] Swap order in BringToFrontAndRestore support function to work around VCL bug. If Application.BringToFront is called while the app is minimized, the Forms unit's WM_ACTIVATEAPP handler inexplicably sets FAppIconic=False, which causes the next Application.Restore call to be a no-op. --- Projects/Src/Setup.ScriptFunc.pas | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Projects/Src/Setup.ScriptFunc.pas b/Projects/Src/Setup.ScriptFunc.pas index 5c862679b..601dabe1d 100644 --- a/Projects/Src/Setup.ScriptFunc.pas +++ b/Projects/Src/Setup.ScriptFunc.pas @@ -1587,8 +1587,9 @@ procedure ScriptFuncLibraryRegister_R(ScriptInterpreter: TPSExec); 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 From 5e6334e70f07b241dbd36ccf596bed565aa411b3 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Wed, 18 Dec 2024 02:39:45 -0600 Subject: [PATCH 10/19] Check if WizardForm is minimized before calling Application.BringToFront. Works around VCL bug. If Application.BringToFront is called while the app is minimized, the Forms unit's WM_ACTIVATEAPP handler inexplicably sets FAppIconic=False, which causes the next Application.Restore call to be a no-op. --- Projects/Src/Setup.MainForm.pas | 6 ++++-- Projects/Src/Setup.WizardForm.pas | 3 ++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Projects/Src/Setup.MainForm.pas b/Projects/Src/Setup.MainForm.pas index 79e7098c2..898b5bb8d 100644 --- a/Projects/Src/Setup.MainForm.pas +++ b/Projects/Src/Setup.MainForm.pas @@ -214,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; @@ -239,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.') diff --git a/Projects/Src/Setup.WizardForm.pas b/Projects/Src/Setup.WizardForm.pas index f713bf346..eca494357 100644 --- a/Projects/Src/Setup.WizardForm.pas +++ b/Projects/Src/Setup.WizardForm.pas @@ -1849,7 +1849,8 @@ function TWizardForm.PrepareToInstall(const WizardComponents, WizardTasks: TStri DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages := False; UpdateCurPageButtonState; end; - Application.BringToFront; + if WindowState <> wsMinimized then { VCL bug workaround } + Application.BringToFront; end; if Result <> '' then begin if PrepareToInstallNeedsRestart then From f1d03c262a49636af337368d4e71e3169718cac1 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Wed, 18 Dec 2024 03:42:22 -0600 Subject: [PATCH 11/19] BrowseFunc: Don't use Application.Handle. The DisableTaskWindows call was the problem. --- Components/BrowseFunc.pas | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/Components/BrowseFunc.pas b/Components/BrowseFunc.pas index ed01ea520..bbedebbaf 100644 --- a/Components/BrowseFunc.pas +++ b/Components/BrowseFunc.pas @@ -86,16 +86,13 @@ function BrowseForFolder(const Prompt: String; var Directory: String; 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 @@ function NewGetOpenOrSaveFileName(const Prompt: String; var FileName: String; 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 @@ function NewGetOpenOrSaveFileName(const Prompt: String; var FileName: String; 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; From 3dc9943825f8c88aa80ef96898334bc9a0946518 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Thu, 19 Dec 2024 02:25:15 -0600 Subject: [PATCH 12/19] Don't allow Application.Restore to show WizardForm if it's hidden. --- Projects/Src/Setup.WizardForm.pas | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Projects/Src/Setup.WizardForm.pas b/Projects/Src/Setup.WizardForm.pas index eca494357..d786dbdb9 100644 --- a/Projects/Src/Setup.WizardForm.pas +++ b/Projects/Src/Setup.WizardForm.pas @@ -211,6 +211,7 @@ TWizardForm = class(TSetupForm) procedure UpdatePage(const PageID: Integer); procedure UpdateSelectTasksPage; procedure WMSysCommand(var Message: TWMSysCommand); message WM_SYSCOMMAND; + procedure WMWindowPosChanging(var Message: TWMWindowPosChanging); message WM_WINDOWPOSCHANGING; public { Public declarations } PrepareToInstallFailureMessage: String; @@ -2684,6 +2685,22 @@ procedure TWizardForm.WMSysCommand(var Message: TWMSysCommand); 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 From e216aae90dfc33581743afefa76095e1ce9725a1 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Fri, 20 Dec 2024 00:15:02 -0600 Subject: [PATCH 13/19] TSetupForm: Don't center inside a hidden or minimized form. --- Projects/Src/Setup.SetupForm.pas | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Projects/Src/Setup.SetupForm.pas b/Projects/Src/Setup.SetupForm.pas index 0b8746d88..f3691055c 100644 --- a/Projects/Src/Setup.SetupForm.pas +++ b/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); From 7da3a11b053051b37a3d07f223fd90939de26f20 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Fri, 20 Dec 2024 04:05:15 -0600 Subject: [PATCH 14/19] Doc: Update for WindowVisible and MainForm removal. --- ISHelp/ISHelpGen/UIsxclassesParser.pas | 1 - ISHelp/isetup.xml | 95 +++++------------------ ISHelp/isxclasses.header2 | 3 +- ISHelp/isxclasses.pas | 4 - ISHelp/isxclasses_wordlists_generated.pas | 24 +++--- ISHelp/isxfunc.xml | 6 -- 6 files changed, 30 insertions(+), 103 deletions(-) diff --git a/ISHelp/ISHelpGen/UIsxclassesParser.pas b/ISHelp/ISHelpGen/UIsxclassesParser.pas index 0421b8a35..be797a8d2 100644 --- a/ISHelp/ISHelpGen/UIsxclassesParser.pas +++ b/ISHelp/ISHelpGen/UIsxclassesParser.pas @@ -248,7 +248,6 @@ procedure TIsxclassesParser.SaveXML(const HeaderFileName, HeaderFileName2, Foote end; end; end; - WriteLn(F, ''); WriteLn(F, ''); WriteLn(F, ''); finally diff --git a/ISHelp/isetup.xml b/ISHelp/isetup.xml index a7268c747..57e8c74d4 100644 --- a/ISHelp/isetup.xml +++ b/ISHelp/isetup.xml @@ -1124,18 +1124,10 @@ DefaultGroupName=My Program
  • AppCopyright
  • -
  • BackColor
  • -
  • BackColor2
  • -
  • BackColorDirection
  • -
  • BackSolid
  • FlatComponentsList
  • SetupIconFile
  • ShowComponentSizes
  • ShowTasksTreeLines
  • -
  • WindowShowCaption
  • -
  • WindowStartMaximized
  • -
  • WindowResizable
  • -
  • WindowVisible
  • WizardImageAlphaFormat
  • WizardImageFile
  • WizardImageStretch
  • @@ -1151,12 +1143,20 @@ DefaultGroupName=My Program
    • AlwaysCreateUninstallIcon
    • +
    • BackColor
    • +
    • BackColor2
    • +
    • BackColorDirection
    • +
    • BackSolid
    • DisableAppendDir
    • DontMergeDuplicateFiles
    • MessagesFile
    • UninstallIconFile
    • UninstallIconName
    • UninstallStyle
    • +
    • WindowResizable
    • +
    • WindowShowCaption
    • +
    • WindowStartMaximized
    • +
    • WindowVisible
    • WizardImageBackColor
    • WizardSmallImageBackColor
    @@ -4032,41 +4032,6 @@ Keep the default set of selected tasks, but deselect the "desktopicon" task:
    - - -A value in the form of $bbggrr, where rr, gg, and bb 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. -clBlue for BackColor,
    clBlack for BackColor2
    - -

    The BackColor directive specifies the color to use at the top (or left, if BackColorDirection=lefttoright) of the setup window's gradient background. BackColor2 specifies the color to use at the bottom (or right).

    -

    The setting of BackColor2 is ignored if BackSolid=yes.

    - -
    -BackColor=clBlue
    -BackColor2=clBlack
    -
    -BackColor=$FF0000
    -BackColor2=$000000
    -
    -
    - -
    - - -toptobottom or lefttoright -toptobottom - -

    This determines the direction of the gradient background on the setup window. If BackColorDirection is toptobottom, it is drawn from top to bottom; if it is lefttoright, it is drawn from left to right.

    - -
    - - -yes or no -no - -

    This specifies whether to use a solid or gradient background on the setup window. If this is yes, the background is a solid color (the color specified by BackColor; BackColor2 is ignored).

    - -
    -

    This required directive specifies the name of the application being installed. Do not include the version number, as that is defined by the AppVersion and/or AppVerName directives. AppName is displayed throughout the Setup program and uninstaller in window titles, wizard pages, and dialog boxes. The value may include constants.

    @@ -4165,8 +4130,7 @@ CreateMutex 0&, 0&, "MyProgramsMutexName" -

    Specifies a copyright message that Setup will display in the bottom-right corner of Setup's background window when WindowVisible is yes.

    -

    The value of this directive is also used as the default value for the VersionInfoCopyright directive if it is not specified.

    +

    The value of this directive is used as the default value for the VersionInfoCopyright directive if it is not specified.

    AppCopyright=Copyright (C) 1997-2005 My Company, Inc.
    @@ -5084,39 +5048,16 @@ DiskSliceSize=1457664
    - -yes or no -yes - -

    If set to no, Setup will be truly "full screen" -- it won't have a caption bar or border, and it will be on top of the taskbar.

    -

    This directive has no effect if WindowVisible is not set to yes.

    - -
    - - -yes or no -yes - -

    If set to yes, the Setup program's background window will initially be displayed in a maximized state, where it won't cover over the taskbar.

    -

    This directive has no effect if WindowVisible is not set to yes.

    - -
    - - -yes or no -yes - -

    If set to no, the user won't be able to resize the Setup program's background window when it's not maximized.

    -

    This directive has no effect if WindowVisible is not set to yes.

    - -
    - - -yes or no -no + + + + + + + + -

    If set to yes, there will be a gradient background window displayed behind the wizard.

    -

    Note that this is considered a legacy feature; it likely will be removed at some point in the future.

    +

    Obsolete in 6.4. 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.

    diff --git a/ISHelp/isxclasses.header2 b/ISHelp/isxclasses.header2 index f4e13cb3d..6d36f58f6 100644 --- a/ISHelp/isxclasses.header2 +++ b/ISHelp/isxclasses.header2 @@ -1,11 +1,10 @@ -

    Below is the list of support classes that can be used from within the Pascal script. There are also three support objects available globally:

    +

    Below is the list of support classes that can be used from within the Pascal script. There are also two support objects available globally:

    Parameter type AnyString means both String and AnsiString can be used.

    diff --git a/ISHelp/isxclasses.pas b/ISHelp/isxclasses.pas index 7166c3c5b..4ab9c5db6 100644 --- a/ISHelp/isxclasses.pas +++ b/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; diff --git a/ISHelp/isxclasses_wordlists_generated.pas b/ISHelp/isxclasses_wordlists_generated.pas index 94b869507..f4e153eeb 100644 --- a/ISHelp/isxclasses_wordlists_generated.pas +++ b/ISHelp/isxclasses_wordlists_generated.pas @@ -27,18 +27,17 @@ interface '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 @@ interface '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;', diff --git a/ISHelp/isxfunc.xml b/ISHelp/isxfunc.xml index ce8853038..196de61eb 100644 --- a/ISHelp/isxfunc.xml +++ b/ISHelp/isxfunc.xml @@ -268,12 +268,6 @@ end;

    Returns the UninstallProgressForm support object, or raises an internal error if the object has not yet been created.

    UninstallProgressForm

    - - GetMainForm - function GetMainForm: TMainForm; -

    Returns the MainForm support object, or raises an internal error if the object has not yet been created.

    -

    MainForm

    -
    From d5e8603909c97269197d085d7482a8b048dfe183 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 22 Dec 2024 02:02:28 -0600 Subject: [PATCH 15/19] Replace "WizardForm.Show" with "WizardForm.Visible := True". Show has a BringToFront call that we don't need. Changing Visible from False to True already brings the window to the front when not minimized. And when it is minimized, we don't want it becoming the active window. This works around the same VCL issue as in preceding commits, where the Forms unit's WM_ACTIVATEAPP handler sets FAppIconic=False even though the window may still be minimized, which causes the next Application.Restore call to be a no-op. --- Projects/Src/Setup.MainForm.pas | 8 ++++---- Projects/Src/Setup.WizardForm.pas | 10 ++++------ 2 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Projects/Src/Setup.MainForm.pas b/Projects/Src/Setup.MainForm.pas index 898b5bb8d..8d5677c2e 100644 --- a/Projects/Src/Setup.MainForm.pas +++ b/Projects/Src/Setup.MainForm.pas @@ -119,7 +119,7 @@ procedure TMainForm.InitializeWizard; WizardForm.SetCurPage(wpWelcome); if InstallMode = imNormal then begin WizardForm.ClickToStartPage; { this won't go past wpReady } - WizardForm.Show; + WizardForm.Visible := True; end else WizardForm.ClickThroughPages; @@ -195,7 +195,7 @@ function TMainForm.Install: Boolean; else begin if WizardWasHidden then begin WizardWasHidden := False; - WizardForm.Show; + WizardForm.Visible := True; end; end; DebugNotifyEntry(seRun, I); @@ -206,7 +206,7 @@ function TMainForm.Install: Boolean; end; finally if WizardWasHidden then - WizardForm.Show; + WizardForm.Visible := True; WindowDisabler.Free; if CheckIfRestartNeeded then begin ChecksumAfter := MakePendingFileRenameOperationsChecksum; @@ -276,7 +276,7 @@ function TMainForm.Install: Boolean; Application.Restore; if InstallMode = imSilent then - WizardForm.Show; + WizardForm.Visible := True; WizardForm.Update; SetStep(ssInstall, False); diff --git a/Projects/Src/Setup.WizardForm.pas b/Projects/Src/Setup.WizardForm.pas index d786dbdb9..e4e1d8fb5 100644 --- a/Projects/Src/Setup.WizardForm.pas +++ b/Projects/Src/Setup.WizardForm.pas @@ -1839,7 +1839,7 @@ function TWizardForm.PrepareToInstall(const WizardComponents, WizardTasks: TStri NextButton.Visible := False; CancelButton.Enabled := False; if InstallMode = imSilent then - WizardForm.Show; + WizardForm.Visible := True; WizardForm.Update; try DownloadTemporaryFileOrExtract7ZipArchiveProcessMessages := True; @@ -2532,7 +2532,7 @@ procedure TWizardForm.NextButtonClick(Sender: TObject); BackButton.Visible := False; NextButton.Visible := False; if InstallMode = imSilent then - WizardForm.Show; + WizardForm.Visible := True; try WizardForm.Update; RmFoundApplications := QueryRestartManager(WizardComponents, WizardTasks) <> ''; @@ -3020,12 +3020,10 @@ procedure TWizardForm.ClickThroughPages; { 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.'); + WizardForm.Visible := True; Application.Restore; - WizardForm.Show; Break; end; end; From 4502469ff72df870dd1a2b5bd9ebe9c95d3550b8 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 22 Dec 2024 03:18:48 -0600 Subject: [PATCH 16/19] Use proper owner on BrowseFunc support function dialogs. --- Projects/Src/Setup.ScriptFunc.HelperFunc.pas | 9 --------- Projects/Src/Setup.ScriptFunc.pas | 8 ++++---- 2 files changed, 4 insertions(+), 13 deletions(-) diff --git a/Projects/Src/Setup.ScriptFunc.HelperFunc.pas b/Projects/Src/Setup.ScriptFunc.HelperFunc.pas index 9e6eb68d4..1fc27a0f8 100644 --- a/Projects/Src/Setup.ScriptFunc.HelperFunc.pas +++ b/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 @@ function GetWizardForm: TWizardForm; 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; diff --git a/Projects/Src/Setup.ScriptFunc.pas b/Projects/Src/Setup.ScriptFunc.pas index 601dabe1d..f0622a95f 100644 --- a/Projects/Src/Setup.ScriptFunc.pas +++ b/Projects/Src/Setup.ScriptFunc.pas @@ -317,23 +317,23 @@ procedure ScriptFuncLibraryRegister_R(ScriptInterpreter: TPSExec); 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; From 5931308522ce9f11ec8e311f45109a697ca09c66 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Sun, 22 Dec 2024 03:29:27 -0600 Subject: [PATCH 17/19] Remove shBackColorHorizontal. --- Projects/Src/Shared.Struct.pas | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Src/Shared.Struct.pas b/Projects/Src/Shared.Struct.pas index 4583daa41..fa19f4aaa 100644 --- a/Projects/Src/Shared.Struct.pas +++ b/Projects/Src/Shared.Struct.pas @@ -53,7 +53,7 @@ interface shAllowNoIcons, shAlwaysRestart, shAlwaysUsePersonalGroup, shEnableDirDoesntExistWarning, shPassword, shAllowRootDirectory, shDisableFinishedPage, shUsePreviousAppDir, - shBackColorHorizontal, shUsePreviousGroup, shUpdateUninstallLogAppName, + shUsePreviousGroup, shUpdateUninstallLogAppName, shUsePreviousSetupType, shDisableReadyMemo, shAlwaysShowComponentsList, shFlatComponentsList, shShowComponentSizes, shUsePreviousTasks, shDisableReadyPage, shAlwaysShowDirOnReadyPage, shAlwaysShowGroupOnReadyPage, From 672d0dd3c40904992abb319d440a0237bf56cdc7 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Mon, 23 Dec 2024 23:41:44 -0600 Subject: [PATCH 18/19] Setup: Don't respect the show command passed by the parent process. --- Projects/Setup.dpr | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/Projects/Setup.dpr b/Projects/Setup.dpr index f96559267..975427014 100644 --- a/Projects/Setup.dpr +++ b/Projects/Setup.dpr @@ -259,6 +259,29 @@ begin 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 } From a670bee440344adf53c3a65186a8e571d0d7d481 Mon Sep 17 00:00:00 2001 From: Jordan Russell Date: Tue, 24 Dec 2024 01:10:25 -0600 Subject: [PATCH 19/19] Update whatsnew. --- whatsnew.htm | 1 + 1 file changed, 1 insertion(+) diff --git a/whatsnew.htm b/whatsnew.htm index 20d2231f0..7b9793c8b 100644 --- a/whatsnew.htm +++ b/whatsnew.htm @@ -91,6 +91,7 @@
  • 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.
  • Added [Setup] section directive EncryptionKeyDerivation to change the number of PBKDF2-HMAC-SHA256 iterations to use from the default of 200000 to another value.
  • 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.
  • +
  • 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 [Setup] section directive WindowVisible, which was used to enable a 1990s-style blue gradient background behind the wizard window, has been dropped.
  • The aspect ratio of Setup's large and small wizard images (as specified by WizardImageFile and WizardSmallImageFile) 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.
  • The New Script Wizard now sets UninstallDisplayIcon when an .exe is chosen as the main executable file.
  • Merged the Inno Setup Preprocessor documentation into the main documentation instead of being separate.