Files
inno-installers/INNO_SETUP_GUIDE.md
cproudlock 28541cd3ed Initial commit: Inno Setup installer packages
Installer packages for GE manufacturing tools:
- BlueSSOFix: Blue SSO authentication fix
- HIDCardPrinter: HID card printer setup
- HPOfflineInstaller: HP printer offline installer
- MappedDrive: Network drive mapping
- PrinterInstaller: General printer installer
- ShopfloorConnect: Shopfloor connectivity tool
- XeroxOfflineInstaller: Xerox printer offline installer

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-30 13:15:54 -05:00

28 KiB

Inno Setup Development Guide

Overview

Inno Setup is a free, open-source Windows installer creator by Jordan Russell and Martijn Laan. It creates professional single-EXE installers for Windows applications.

What is Inno Setup?

Inno Setup creates Windows installers that can:

  • Package applications into single EXE installers
  • Install files, create shortcuts, modify registry
  • Support 64-bit and Arm64 Windows architectures
  • Provide uninstall capabilities
  • Support multiple languages
  • Run silent/unattended installations
  • Execute custom scripts during installation

Notable users: Visual Studio Code, Git for Windows, Embarcadero Delphi

Supported Windows Versions

  • Windows 11, 10, 8.1, 8, 7
  • Windows Server 2022, 2019, 2016, 2012
  • All versions since 2006
  • x64 and Arm64 architectures

Our Inno Setup Template

Based on /home/camp/projects/inno/MappedDrive/MappedDrive.iss

This template demonstrates:

  • Modern wizard UI with custom branding
  • Custom wizard pages with user input
  • Password input fields
  • Multi-option selection pages
  • Embedded PowerShell script execution
  • Environment variable passing
  • No installation directory (utility-style installer)
  • Admin privileges requirement
  • Custom icons and images

Inno Setup Script Structure

File Format

  • Extension: .iss (Inno Setup Script)
  • Encoding: Plain text, UTF-8 recommended
  • Comments: Lines starting with ; or //

Script Sections

All Inno Setup scripts are divided into sections marked with [SectionName].

[Setup] - Core Configuration

Defines installer metadata and behavior.

Common Parameters from Our Template:

[Setup]
AppId={{GUID}}                     ; Unique identifier (use https://guidgenerator.com)
AppName=Your Application Name       ; Display name
AppVersion=1.0                      ; Version number
AppPublisher=Your Company           ; Publisher name
AppPublisherURL=http://example.com  ; Website
AppSupportURL=http://example.com    ; Support site
AppUpdatesURL=http://example.com    ; Updates page

; Installation behavior
CreateAppDir=yes                    ; Create installation directory? (no for utilities)
ChangesAssociations=no              ; Register file associations?
PrivilegesRequired=admin            ; Require admin rights? (admin/lowest/none)

; Output configuration
OutputDir=C:\Output                 ; Where to save installer EXE
OutputBaseFilename=MyInstaller      ; Installer filename (without .exe)
SolidCompression=yes                ; Better compression (slower build)

; UI customization
WizardStyle=modern                  ; modern or classic
SetupIconFile=icon.ico              ; Installer icon
WizardImageFile=image.bmp           ; Left side image (164x314px)
WizardSmallImageFile=small.bmp      ; Top right image (55x58px)
DisableWelcomePage=no               ; Show welcome page?

; Uninstaller
CreateUninstallRegKey=no            ; Create uninstall entry? (no for utilities)

Other Useful Parameters:

DefaultDirName={autopf}\MyApp       ; Default install path
DefaultGroupName=My Application     ; Start menu folder
LicenseFile=license.txt             ; Show license agreement
InfoBeforeFile=readme.txt           ; Show before install
InfoAfterFile=info.txt              ; Show after install
Compression=lzma2                   ; Compression algorithm (lzma2/lzma/zip/bzip)
ArchitecturesInstallIn64BitMode=x64 arm64  ; 64-bit mode for these architectures
UninstallDisplayIcon={app}\MyApp.exe       ; Uninstaller icon

[Languages] - Localization

Define supported languages.

[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
Name: "spanish"; MessagesFile: "compiler:Languages\Spanish.isl"
Name: "french"; MessagesFile: "compiler:Languages\French.isl"

Built-in languages: English, French, German, Spanish, Italian, Dutch, Portuguese, and 30+ others.


[Messages] - Custom Text

Override default installer text.

From Our Template:

[Messages]
WelcomeLabel2=This utility will help you reconnect your mapped network drives...

Common Messages to Override:

  • WelcomeLabel1 - Welcome page title
  • WelcomeLabel2 - Welcome page description
  • FinishedLabel - Completion message
  • ButtonInstall - Install button text (default: "Install")
  • ButtonNext - Next button text
  • ButtonCancel - Cancel button text

Full list: https://jrsoftware.org/ishelp/index.php?topic=messages


[Files] - Files to Install

Copy files from source to destination.

[Files]
Source: "C:\MyApp\MyApp.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\MyApp\data\*"; DestDir: "{app}\data"; Flags: ignoreversion recursesubdirs
Source: "C:\MyApp\config.ini"; DestDir: "{app}"; Flags: onlyifdoesntexist

Common Flags:

  • ignoreversion - Always copy, overwrite existing
  • recursesubdirs - Include subdirectories
  • onlyifdoesntexist - Don't overwrite existing files
  • createallsubdirs - Create empty subdirectories
  • restartreplace - Replace on reboot if file is locked
  • regserver - Register DLL/OCX after install
  • isreadme - Offer to open file after install

[Dirs] - Create Directories

Create empty directories.

[Dirs]
Name: "{app}\logs"
Name: "{app}\cache"; Permissions: users-modify
Name: "{commonappdata}\MyApp\data"

[Icons] - Create Shortcuts

Create Start Menu, Desktop, or other shortcuts.

[Icons]
Name: "{autoprograms}\My Application"; Filename: "{app}\MyApp.exe"
Name: "{autodesktop}\My Application"; Filename: "{app}\MyApp.exe"
Name: "{autostartup}\My Application"; Filename: "{app}\MyApp.exe"
Name: "{group}\Uninstall My App"; Filename: "{uninstallexe}"

Common Locations:

  • {autoprograms} - Start Menu programs folder
  • {autodesktop} - Desktop
  • {autostartup} - Startup folder (runs on boot)
  • {group} - App's Start Menu folder (defined by DefaultGroupName)
  • {commonstartmenu} - All Users Start Menu

[Registry] - Modify Windows Registry

Add, modify, or delete registry keys.

[Registry]
Root: HKLM; Subkey: "Software\MyCompany\MyApp"; ValueType: string; ValueName: "InstallPath"; ValueData: "{app}"
Root: HKCU; Subkey: "Software\MyCompany\MyApp"; ValueType: dword; ValueName: "Version"; ValueData: "1"
Root: HKLM; Subkey: "Software\MyCompany\MyApp"; Flags: uninsdeletekey

Value Types:

  • string - Text value (REG_SZ)
  • expandsz - Expandable string (REG_EXPAND_SZ)
  • dword - 32-bit number (REG_DWORD)
  • qword - 64-bit number (REG_QWORD)
  • binary - Binary data (REG_BINARY)
  • multisz - Multi-string (REG_MULTI_SZ)

Common Flags:

  • uninsdeletekey - Delete entire key on uninstall
  • uninsdeletekeyifempty - Delete key if empty on uninstall
  • uninsdeletevalue - Delete value on uninstall

[Run] - Execute Programs After Install

Run programs at the end of installation.

[Run]
Filename: "{app}\MyApp.exe"; Description: "Launch My Application"; Flags: nowait postinstall skipifsilent
Filename: "{app}\setup.exe"; Parameters: "/config"; Flags: runhidden waituntilterminated

Common Flags:

  • nowait - Don't wait for program to finish
  • waituntilterminated - Wait for program to finish before continuing
  • postinstall - Show checkbox, let user choose to run
  • skipifsilent - Don't run during silent install
  • runhidden - Hide window
  • runasoriginaluser - Run as non-admin even if installer is admin

[UninstallRun] - Execute Programs During Uninstall

Run programs when uninstalling.

[UninstallRun]
Filename: "{app}\cleanup.exe"; Parameters: "/silent"

[Code] - Pascal Script

Advanced scripting for custom installer logic.

Our Template Demonstrates:

  • Custom wizard pages
  • User input collection
  • Password fields
  • Validation logic
  • Executing PowerShell scripts
  • Passing data via environment variables
  • External DLL calls

Basic Structure:

[Code]
// Global variables
var
  MyVariable: String;

// Initialize wizard
procedure InitializeWizard();
begin
  // Create custom pages here
end;

// Validate page before continuing
function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;

  if CurPageID = wpWelcome then
  begin
    // Validate something
    if SomeCondition then
    begin
      MsgBox('Error message', mbError, MB_OK);
      Result := False;
    end;
  end;
end;

// Execute after installation
procedure CurStepChanged(CurStep: TSetupStep);
begin
  if CurStep = ssPostInstall then
  begin
    // Do something after files installed
  end;
end;

Constants (Directory/Path Placeholders)

Inno Setup uses constants wrapped in {brackets} for common paths.

Common Application Directories

{app}           ; Installation directory (e.g., C:\Program Files\MyApp)
{win}           ; Windows directory (e.g., C:\Windows)
{sys}           ; Windows System32 directory
{syswow64}      ; System32 for 32-bit apps on 64-bit Windows
{tmp}           ; Temporary directory for this install session

User Directories

{userappdata}   ; C:\Users\{username}\AppData\Roaming
{localappdata}  ; C:\Users\{username}\AppData\Local
{userdocs}      ; C:\Users\{username}\Documents
{userdesktop}   ; C:\Users\{username}\Desktop
{userpf}        ; C:\Users\{username}\AppData\Local\Programs (non-admin installs)

Common Directories (All Users)

{commonappdata} ; C:\ProgramData
{commonpf}      ; C:\Program Files
{commonpf32}    ; C:\Program Files (x86) on 64-bit, C:\Program Files on 32-bit
{commonpf64}    ; C:\Program Files (64-bit only)
{commondocs}    ; C:\Users\Public\Documents
{commondesktop} ; C:\Users\Public\Desktop

Shortcuts

{autoprograms}  ; User's Start Menu\Programs
{autostartup}   ; User's Startup folder
{autodesktop}   ; User's Desktop
{group}         ; App's Start Menu folder (DefaultGroupName)
{commonstartmenu} ; All Users Start Menu

Other Useful Constants

{uninstallexe}  ; Path to uninstaller
{src}           ; Directory where installer EXE is located
{sd}            ; System drive (usually C:)
{%USERNAME}     ; Current Windows username (environment variable)
{computername}  ; Computer name

Custom Wizard Pages (Pascal Script)

Creating Input Pages

Our Template Uses These Page Types:

1. Input Option Page (Checkboxes/Radio Buttons)

var
  ServerSelectionPage: TInputOptionWizardPage;

procedure InitializeWizard();
begin
  ServerSelectionPage := CreateInputOptionPage(wpWelcome,
    'Select Servers to Reconnect',
    'Choose which network drives you need to reconnect',
    'Select the servers below.',
    False,  // Exclusive (radio buttons if True, checkboxes if False)
    False); // ListBox style?

  ServerSelectionPage.Add('Option 1 text');
  ServerSelectionPage.Add('Option 2 text');

  // Set defaults
  ServerSelectionPage.Values[0] := True;  // First option checked
  ServerSelectionPage.Values[1] := False; // Second option unchecked
end;

Reading Values:

if ServerSelectionPage.Values[0] then
begin
  // Option 1 was selected
end;

2. Input Query Page (Text Fields)

var
  PasswordPage: TInputQueryWizardPage;

procedure InitializeWizard();
begin
  PasswordPage := CreateInputQueryPage(wpWelcome,
    'Enter Network Credentials',
    'Please enter your password',
    'Enter your password below:');

  PasswordPage.Add('Password:', True);  // True = password field (masked)
  PasswordPage.Add('Username:', False); // False = regular text field
end;

Reading Values:

UserPassword := PasswordPage.Values[0];
UserName := PasswordPage.Values[1];

3. Output Progress Page (Progress Bar)

var
  ProgressPage: TOutputProgressWizardPage;

procedure InitializeWizard();
begin
  ProgressPage := CreateOutputProgressPage('Processing...',
                                            'Please wait while we process your data.');
end;

// Later, when executing
procedure ProcessData();
begin
  ProgressPage.SetProgress(0, 100);
  ProgressPage.Show;
  try
    // Do work
    ProgressPage.SetProgress(50, 100);
    // More work
    ProgressPage.SetProgress(100, 100);
  finally
    ProgressPage.Hide;
  end;
end;

Page Order and IDs

Built-in Page IDs:

wpWelcome       ; Welcome page
wpLicense       ; License agreement
wpPassword      ; Password prompt
wpInfoBefore    ; Pre-install info
wpUserInfo      ; User info (name, company)
wpSelectDir     ; Installation directory
wpSelectComponents ; Component selection
wpSelectProgramGroup ; Start menu folder
wpSelectTasks   ; Task selection (checkboxes)
wpReady         ; Ready to Install
wpPreparing     ; Preparing to Install
wpInstalling    ; Installing (progress bar)
wpInfoAfter     ; Post-install info
wpFinished      ; Finished page

Insert Custom Pages:

// After wpWelcome
MyPage := CreateInputQueryPage(wpWelcome, 'Title', 'Subtitle', 'Description');

// Before wpReady
MyPage := CreateInputQueryPage(wpSelectDir, 'Title', 'Subtitle', 'Description');

Validation and Logic

Validate Before Next Page:

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;  // Allow by default

  if CurPageID = PasswordPage.ID then
  begin
    if Trim(PasswordPage.Values[0]) = '' then
    begin
      MsgBox('Password cannot be empty!', mbError, MB_OK);
      Result := False;  // Prevent advancing
    end;
  end;
end;

Skip Pages Conditionally:

function ShouldSkipPage(PageID: Integer): Boolean;
begin
  Result := False;

  if PageID = wpSelectComponents then
    Result := True;  // Skip component selection
end;

Executing External Programs

From [Run] Section

[Run]
Filename: "{app}\MyApp.exe"; Description: "Launch application"; Flags: postinstall nowait
Filename: "cmd.exe"; Parameters: "/c echo Done"; Flags: runhidden waituntilterminated

From Pascal Code

var
  ResultCode: Integer;

// Execute and wait
if Exec('powershell.exe', '-File "script.ps1"', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
  if ResultCode = 0 then
    MsgBox('Success!', mbInformation, MB_OK)
  else
    MsgBox('Failed with code ' + IntToStr(ResultCode), mbError, MB_OK);
end;

Exec Parameters:

Exec(Filename, Parameters, WorkingDir, ShowCmd, Wait, ResultCode)

; ShowCmd options:
SW_SHOW     ; Show window normally
SW_HIDE     ; Hide window
SW_SHOWNORMAL ; Normal window
SW_MAXIMIZE ; Maximized window

; Wait options:
ewNoWait              ; Don't wait, return immediately
ewWaitUntilTerminated ; Wait until program exits
ewWaitUntilIdle       ; Wait until program is idle

PowerShell Integration (Our Template Pattern)

Our MappedDrive template demonstrates:

  1. Build PowerShell script as a string in Pascal
  2. Save script to temporary file
  3. Pass sensitive data via environment variable
  4. Execute PowerShell script
  5. Clean up temporary files and variables

Code Pattern:

var
  ScriptPath: String;
  PowerShellScript: String;
  ResultCode: Integer;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  if CurPageID = wpReady then
  begin
    // 1. Build PowerShell script
    PowerShellScript :=
      '$username = "' + Username + '"' + #13#10 +
      '$password = [System.Environment]::GetEnvironmentVariable("TEMP_PASSWORD","Process")' + #13#10 +
      'Write-Host "Hello, $username"' + #13#10;

    // 2. Save to temp file
    ScriptPath := ExpandConstant('{tmp}\script.ps1');
    SaveStringToFile(ScriptPath, PowerShellScript, False);

    // 3. Set environment variable (for sensitive data)
    SetEnvironmentVariable('TEMP_PASSWORD', UserPassword);

    // 4. Execute PowerShell
    Exec('powershell.exe',
         '-NoProfile -ExecutionPolicy Bypass -File "' + ScriptPath + '"',
         '', SW_SHOW, ewWaitUntilTerminated, ResultCode);

    // 5. Cleanup
    SetEnvironmentVariable('TEMP_PASSWORD', '');
    DeleteFile(ScriptPath);
  end;
end;

Why This Pattern?

  • Security: Password never written to disk, only in memory
  • Flexibility: Can build complex PowerShell scripts dynamically
  • Clean: Temporary files removed after execution
  • Visibility: User sees PowerShell output (or use SW_HIDE)

Environment Variables

Reading Environment Variables

var
  UserName: String;

UserName := GetEnv('USERNAME');
UserName := ExpandConstant('{%USERNAME}');  // Alternative syntax

Setting Environment Variables (Windows API Call)

// Declare external function
function SetEnvironmentVariable(lpName: String; lpValue: String): Boolean;
external 'SetEnvironmentVariableW@kernel32.dll stdcall';

// Use it
SetEnvironmentVariable('MY_VAR', 'MyValue');

Scope: Process-level only (not permanent, cleared when installer exits).


Working with Files in Pascal Script

Save String to File

SaveStringToFile(FileName, Content, Append)

SaveStringToFile('C:\output.txt', 'Hello World', False);  // Overwrite
SaveStringToFile('C:\output.txt', 'New line', True);      // Append

Load File to String

var
  Content: String;

if LoadStringFromFile('C:\input.txt', Content) then
  MsgBox(Content, mbInformation, MB_OK);

Delete File

DeleteFile('C:\temp\file.txt');

File Exists Check

if FileExists('C:\MyApp\config.ini') then
  MsgBox('Config found!', mbInformation, MB_OK);

Directory Exists Check

if DirExists('C:\MyApp') then
  MsgBox('Directory exists!', mbInformation, MB_OK);

Common Pascal Script Functions

Message Boxes

MsgBox('Message text', MessageType, Buttons)

MsgBox('Installation complete!', mbInformation, MB_OK);
MsgBox('Are you sure?', mbConfirmation, MB_YESNO);
MsgBox('Error occurred!', mbError, MB_OK);
MsgBox('Warning!', mbWarning, MB_OK);

// Check result
if MsgBox('Continue?', mbConfirmation, MB_YESNO) = IDYES then
begin
  // User clicked Yes
end;

Message Types:

  • mbInformation - Info icon
  • mbConfirmation - Question icon
  • mbError - Error icon
  • mbWarning - Warning icon
  • mbCriticalError - Critical error icon

Button Types:

  • MB_OK - OK button only
  • MB_OKCANCEL - OK and Cancel
  • MB_YESNO - Yes and No
  • MB_YESNOCANCEL - Yes, No, Cancel
  • MB_RETRYCANCEL - Retry and Cancel

String Functions

Trim(S)              ; Remove leading/trailing spaces
UpperCase(S)         ; Convert to uppercase
LowerCase(S)         ; Convert to lowercase
Length(S)            ; String length
Copy(S, Index, Count); Extract substring
Pos(Substr, S)       ; Find position of substring
StringChangeEx(S, Find, Replace, ReplaceAll); Replace text

Conversion Functions

IntToStr(123)        ; Integer to string: "123"
StrToInt('123')      ; String to integer: 123
FloatToStr(1.5)      ; Float to string: "1.5"
StrToFloat('1.5')    ; String to float: 1.5

System Functions

GetUserNameString()  ; Current Windows username
GetComputerNameString(); Computer name
ExpandConstant('{app}'); Expand path constant
IsAdmin()            ; Is installer running as admin?
IsWin64()            ; Is Windows 64-bit?

Building the Installer

Using Inno Setup Compiler GUI

  1. Open Inno Setup Compiler
  2. File → Open → Select .iss file
  3. Build → Compile (or press F9)
  4. Output EXE created in OutputDir

Command Line Compilation

# Windows
"C:\Program Files (x86)\Inno Setup 6\ISCC.exe" "C:\path\to\script.iss"

# Output
# Successful compile: Exit code 0
# Compilation errors: Exit code 1

Automated Build Script

@echo off
set INNO="C:\Program Files (x86)\Inno Setup 6\ISCC.exe"
set SCRIPT="C:\Projects\MyApp\installer.iss"

echo Building installer...
%INNO% %SCRIPT%

if %ERRORLEVEL% EQU 0 (
    echo Success! Installer created.
) else (
    echo Build failed!
    exit /b 1
)

Our Project Template Assets

Required Files for MappedDrive Template

MappedDrive/
├── MappedDrive.iss          ; Main script
├── gea-logo.ico             ; Setup icon (for EXE)
├── patrick.bmp              ; Large wizard image (164x314px)
└── patrick-sm.bmp           ; Small wizard image (55x58px)

Image Specifications

  • SetupIconFile: .ico format, 32x32 or 48x48px
  • WizardImageFile: .bmp format, 164x314px (left side of wizard)
  • WizardSmallImageFile: .bmp format, 55x58px (top-right corner)

Creating a New Project (Quick Start)

1. Create Project Directory

cd ~/projects/inno
mkdir MyNewProject
cd MyNewProject

2. Copy Template

# Copy the MappedDrive template as starting point
cp ../MappedDrive/MappedDrive.iss ./MyProject.iss
cp ../MappedDrive/*.bmp .
cp ../MappedDrive/*.ico .

3. Edit Basic Settings

[Setup]
AppId={{NEW-GUID-HERE}}           ; Generate at https://guidgenerator.com
AppName=My New Application
AppVersion=1.0
AppPublisher=WJDT
OutputBaseFilename=MyNewApp

; Adjust these based on your needs
CreateAppDir=yes                   ; yes if installing files
PrivilegesRequired=lowest          ; lowest/admin based on needs

4. Add Your Files

[Files]
Source: "C:\Source\MyApp.exe"; DestDir: "{app}"; Flags: ignoreversion

5. Customize Wizard Pages

  • Modify or remove custom pages in [Code] section
  • Adjust welcome message in [Messages]
  • Update PowerShell script logic if needed

6. Build and Test

# Build on Windows (can't build on Linux, Inno Setup is Windows-only)
# Copy .iss and assets to Windows, then compile

Best Practices

Security

  • DO: Pass sensitive data via environment variables (cleared after use)
  • DO: Use temporary files for scripts, delete after execution
  • DON'T: Hardcode passwords or secrets in .iss file
  • DON'T: Write sensitive data to permanent files

Performance

  • Use SolidCompression=yes for smaller installers (slower build)
  • Use Compression=lzma2 for best compression ratio
  • Set DiskSpanning=no for single-file installers

User Experience

  • Always provide meaningful WelcomeLabel2 message
  • Use postinstall flag with skipifsilent for optional launch
  • Show progress/feedback for long operations
  • Provide clear error messages with actions to take

Code Organization

  • Use constants for repeated values
  • Comment complex Pascal code
  • Break long PowerShell scripts into logical sections
  • Validate all user inputs before proceeding

Testing

  • Test on clean VM (no previous installs)
  • Test with non-admin user (if PrivilegesRequired=lowest)
  • Test silent install: MyInstaller.exe /VERYSILENT /NORESTART
  • Test uninstall process

Common Patterns from MappedDrive Template

Pattern 1: Custom Input Collection

var
  InputPage: TInputQueryWizardPage;
  UserInput: String;

procedure InitializeWizard();
begin
  InputPage := CreateInputQueryPage(wpWelcome, 'Title', 'Subtitle', 'Prompt');
  InputPage.Add('Enter value:', False);
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;
  if CurPageID = InputPage.ID then
  begin
    UserInput := InputPage.Values[0];
    if UserInput = '' then
    begin
      MsgBox('Value required!', mbError, MB_OK);
      Result := False;
    end;
  end;
end;

Pattern 2: Multi-Option Selection

var
  OptionPage: TInputOptionWizardPage;

procedure InitializeWizard();
begin
  OptionPage := CreateInputOptionPage(wpWelcome, 'Title', 'Subtitle', 'Prompt', False, False);
  OptionPage.Add('Option 1');
  OptionPage.Add('Option 2');
  OptionPage.Values[0] := True;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
  Result := True;
  if CurPageID = OptionPage.ID then
  begin
    if not (OptionPage.Values[0] or OptionPage.Values[1]) then
    begin
      MsgBox('Select at least one option!', mbError, MB_OK);
      Result := False;
    end;
  end;
end;

Pattern 3: Confirmation Dialog

if MsgBox('Are you sure you want to proceed?', mbConfirmation, MB_YESNO) = IDYES then
begin
  // User confirmed
end
else
begin
  // User cancelled
end;

Pattern 4: Dynamic PowerShell Execution

var
  PSScript: String;
  ScriptPath: String;
  ResultCode: Integer;

// Build script dynamically
PSScript := 'Write-Host "Hello"' + #13#10;
PSScript := PSScript + 'Write-Host "World"' + #13#10;

// Save and execute
ScriptPath := ExpandConstant('{tmp}\temp.ps1');
SaveStringToFile(ScriptPath, PSScript, False);
Exec('powershell.exe', '-NoProfile -ExecutionPolicy Bypass -File "' + ScriptPath + '"',
     '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
DeleteFile(ScriptPath);

Debugging Tips

Enable Debug Mode

Add to [Setup]:

[Setup]
OutputDebugString=yes

View Installer Log

Run installer with /LOG:

MyInstaller.exe /LOG="C:\install.log"

Test in Virtual Machine

  • Use Windows Sandbox or VM for clean testing
  • Snapshot before install, restore after test

Common Issues

  1. "Error reading file": Check file paths in [Files] section
  2. "Access denied": Verify PrivilegesRequired=admin if needed
  3. PowerShell fails: Check execution policy and script syntax
  4. Custom page not appearing: Verify page ID in CreateInputXXXPage(PageID, ...)

Silent Installation

Command Line Parameters

MyInstaller.exe /SILENT          ; Silent mode, shows progress
MyInstaller.exe /VERYSILENT      ; Very silent mode, no UI
MyInstaller.exe /SUPPRESSMSGBOXES ; Suppress message boxes
MyInstaller.exe /NORESTART       ; Don't restart computer
MyInstaller.exe /DIR="C:\MyApp"  ; Override install directory
MyInstaller.exe /LOG="C:\log.txt"; Create install log

Combine Parameters

MyInstaller.exe /VERYSILENT /NORESTART /LOG="C:\install.log"

Unattended Install Script

@echo off
MyInstaller.exe /VERYSILENT /NORESTART /LOG="C:\install.log"
if %ERRORLEVEL% EQU 0 (
    echo Installation successful
) else (
    echo Installation failed with code %ERRORLEVEL%
)


Quick Reference Summary

Task Code Example
Create installer [Setup] AppName=MyApp
Install files [Files] Source: "app.exe"; DestDir: "{app}"
Create shortcut [Icons] Name: "{autodesktop}\MyApp"; Filename: "{app}\app.exe"
Custom page CreateInputQueryPage(wpWelcome, 'Title', 'Desc', 'Prompt')
Execute program Exec('cmd.exe', '/c echo done', '', SW_SHOW, ewWaitUntilTerminated, Code)
Message box MsgBox('Hello', mbInformation, MB_OK)
Get username GetUserNameString()
Check if admin IsAdmin()
Build installer Press F9 in Inno Setup Compiler
Silent install MyInstaller.exe /VERYSILENT

Template Location: /home/camp/projects/inno/MappedDrive/MappedDrive.iss Documentation: This file Last Updated: 2025-10-10