Adding Minimize and Restore Transitions (Animations) to Inno Setup Wizard Form:
In Unit Wizard,
Change TWizardForm.CreateParams
like this:
procedure TWizardForm.CreateParams(var Params: TCreateParams);
begin
inherited;
{ Ensure the form is on top of MainForm by making MainForm
the "parent" of the form when *MainForm is set to Visible*. }
if shWindowVisible in SetupHeader.Options then
Params.WndParent := MainForm.Handle
else
Params.WndParent := GetDesktopWindow;
end;
Change TWizardForm.WMSysCommand
like this:
procedure TWizardForm.WMSysCommand(var Message: TWMSysCommand);
begin
if Message.CmdType and $FFF0 = SC_MINIMIZE then begin
{ 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. }
if shWindowVisible in SetupHeader.Options then
Application.Minimize
else
ShowWindow(WizardForm.Handle, SW_MINIMIZE);
end
else
if Message.CmdType and $FFF0 = SC_RESTORE then begin
if shWindowVisible in SetupHeader.Options then
Application.Restore
else
ShowWindow(WizardForm.Handle, SW_RESTORE);
end;
if Message.CmdType = 9999 then
MainForm.ShowAboutBox
else
inherited;
end;
Declare a new procedure called TWizardForm.FormShow
like shown below:
procedure FormShow(Sender: TObject);
Declare it like below in Implementation
Section of Unit Wizard.
procedure TWizardForm.FormShow(Sender: TObject);
begin
if not(shWindowVisible in SetupHeader.Options) then
ShowWindow(Application.Handle, SW_HIDE);
end;
Finally, add this TWizardForm.FormShow
as OnShow Form Event of the WizardForm.
You're almost done! Now Wizard Window should display Restore and Minimize Animations as you expect.
Fixing MessageBox Parent Window issue after adding Minimize Transitions (Animations) to the Inno Setup Wizard:
Note: This must be done to prevent Logged Wizard Message Boxes (Whose can be logged with Inno Setup Compiler Log) from sometimes displaying two Taskbar Buttons even WizardForm is Visible.
In the Section { Variables for command line parameters }
of Unit Main, declare a new Boolean Variable like this:
IsApplicationRunning: Boolean;
In Unit Main,
Change the procedure AbortInit
like this:
procedure AbortInit(const Msg: TSetupMessageID);
begin
IsApplicationRunning := False;
LoggedMsgBox(SetupMessages[Msg], '', mbCriticalError, MB_OK, True, IDOK);
Abort;
end;
Change the procedure AbortInitFmt1
like this:
procedure AbortInitFmt1(const Msg: TSetupMessageID; const Arg1: String);
begin
IsApplicationRunning := False;
LoggedMsgBox(FmtSetupMessage(Msg, [Arg1]), '', mbCriticalError, MB_OK, True, IDOK);
Abort;
end;
Change the procedure AbortInitServicePackRequired
like this:
procedure AbortInitServicePackRequired(const ServicePack: Word);
begin
IsApplicationRunning := False;
LoggedMsgBox(FmtSetupMessage(msgWindowsServicePackRequired, ['Windows', IntToStr(Hi(ServicePack))]), '', mbCriticalError, MB_OK, True, IDOK);
Abort;
end;
In Unit Wizard,
Modify the previously added procedure TWizardForm.FormShow
like this:
procedure TWizardForm.FormShow(Sender: TObject);
begin
if not(shWindowVisible in SetupHeader.Options) then
ShowWindow(Application.Handle, SW_HIDE);
IsApplicationRunning := True;
end;
In Unit CmnFunc,
Add Wizard
and Main
to the Uses Section in Implementation
of Unit CmnFunc.
Change the procedure AppMessageBox
like this:
function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer;
var
ActiveWindow: HWND;
MessageHandler: HWND;
WindowList: Pointer;
{$IFNDEF IS_D4}
DidMove: Boolean;
OldRect: TRect;
{$ENDIF}
begin
if MessageBoxRightToLeft then
Flags := Flags or (MB_RTLREADING or MB_RIGHT);
if IsApplicationRunning = False then
MessageHandler := Application.Handle
else
MessageHandler := WizardForm.Handle;
{ If the application window isn't currently visible, show the message box
with no owner window so it'll get a taskbar button }
if IsIconic(MessageHandler) or (GetWindowLong(MessageHandler, GWL_STYLE) and WS_VISIBLE = 0) or (GetWindowLong(MessageHandler, GWL_EXSTYLE) and WS_EX_TOOLWINDOW <> 0) then begin
ActiveWindow := GetActiveWindow;
WindowList := DisableTaskWindows(0);
try
{ Note: DisableTaskWindows doesn't disable invisible windows.
MB_TASKMODAL will ensure that Application.Handle gets disabled too. }
Result := MessageBox(0, Text, Caption, Flags or MB_TASKMODAL);
finally
EnableTaskWindows(WindowList);
SetActiveWindow(ActiveWindow);
end;
Exit;
end;
TriggerMessageBoxCallbackFunc(Flags, False);
try
{$IFDEF IS_D4}
{ On Delphi 4+, simply call Application.MessageBox }
Result := Application.MessageBox(Text, Caption, Flags);
{$ELSE}
{ Use custom implementation on Delphi 2 and 3. The Flags parameter is
incorrectly declared as a Word on Delphi 2's Application.MessageBox, and
there is no support for multiple monitors. }
DidMove := MoveAppWindowToActiveWindowMonitor(OldRect);
try
ActiveWindow := GetActiveWindow;
WindowList := DisableTaskWindows(0);
try
Result := MessageBox(Application.Handle, Text, Caption, Flags);
finally
EnableTaskWindows(WindowList);
SetActiveWindow(ActiveWindow);
end;
finally
if DidMove then
SetWindowPos(Application.Handle, 0,
OldRect.Left + ((OldRect.Right - OldRect.Left) div 2),
OldRect.Top + ((OldRect.Bottom - OldRect.Top) div 2),
0, 0, SWP_NOACTIVATE or SWP_NOREDRAW or SWP_NOSIZE or SWP_NOZORDER);
end;
{$ENDIF}
finally
TriggerMessageBoxCallbackFunc(Flags, True);
end;
end;
Now all Logged and any other Message Boxes will be displayed Normally!
Now, Compile the Setup Program (Setup.e32) using a Recommended Compiler in the ReadMe File and copy it to the directory where you installed Inno Setup.
Note: The installed version of Inno Setup Unicode or Ansi must match the Version of the source code of Inno Setup which you're modified to Re-compile. Or you can Compile whole Inno Setup Project and Copy - Replace this modified and Re-compiled Setup Program (Setup.e32) to the directory where you compiled Inno Setup.
After Re-compiling Setup Program, you need to add following codes to the Pascal Script.
[Files]
Source: "InnoCallback.dll"; Flags: dontcopy
[Code]
#ifdef UNICODE
#define AW "W"
#else
#define AW "A"
#endif
const
GWL_WNDPROC = -4;
SC_ABOUTBOX = 9999;
SC_RESTORE = $F120;
SC_MINIMIZE = $F020;
WM_SYSCOMMAND = $0112;
Type
WPARAM = UINT_PTR;
LPARAM = LongInt;
LRESULT = LongInt;
TWindowProc = function(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
PrevWndProc: LongInt;
function CallWindowProc(lpPrevWndFunc: LongInt; hWnd: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
external 'CallWindowProc{#AW}@user32.dll stdcall';
function WrapWindowProc(Callback: TWindowProc; ParamCount: Integer): LongWord;
external 'wrapcallback@files:InnoCallback.dll stdcall';
function SetWindowLong(hWnd: HWND; nIndex: Integer; dwNewLong: LongInt): LongInt;
external 'SetWindowLong{#AW}@user32.dll stdcall';
function Wizard_WMSYSCOMMAND(hwnd: HWND; uMsg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
begin
if (uMsg = WM_SYSCOMMAND) and (wParam and $FFF0 = SC_MINIMIZE) then begin
//SOMETHING LIKE BASS_Pause();.
Log('Wizard Window has been Minimized.');
end;
if (uMsg = WM_SYSCOMMAND) and (wParam and $FFF0 = SC_RESTORE) then begin
//SOMETHING LIKE BASS_Start();.
Log('Wizard Window has been Restored.');
end;
if (uMsg = WM_SYSCOMMAND) and (wParam = SC_ABOUTBOX) then begin
Result := 0;
MainForm.ShowAboutBox;
end
else
Result := CallWindowProc(PrevWndProc, hwnd, uMsg, wParam, lParam);
end;
procedure InitializeWizard();
begin
PrevWndProc := SetWindowLong(WizardForm.Handle, GWL_WNDPROC, WrapWindowProc(@Wizard_WMSYSCOMMAND, 4));
end;
procedure DeinitializeSetup();
begin
SetWindowLong(WizardForm.Handle, GWL_WNDPROC, PrevWndProc);
end;
Now, you should be notified immediately when WizardForm Minimizes or Restores via Compiler Log Messages. You can Pause or Resume Music according to your code by adding them in the function Wizard_WMSYSCOMMAND
.