# 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.

- **Official Website**: https://jrsoftware.org/
- **Documentation**: https://jrsoftware.org/ishelp/
- **Our Projects Location**: `~/projects/inno/`

## 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:**
```pascal
[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:**
```pascal
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.

```pascal
[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:**
```pascal
[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.

```pascal
[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.

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

---

#### **[Icons]** - Create Shortcuts
Create Start Menu, Desktop, or other shortcuts.

```pascal
[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.

```pascal
[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.

```pascal
[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.

```pascal
[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:**
```pascal
[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
```pascal
{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
```pascal
{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)
```pascal
{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
```pascal
{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
```pascal
{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)
```pascal
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:**
```pascal
if ServerSelectionPage.Values[0] then
begin
  // Option 1 was selected
end;
```

---

#### 2. **Input Query Page** (Text Fields)
```pascal
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:**
```pascal
UserPassword := PasswordPage.Values[0];
UserName := PasswordPage.Values[1];
```

---

#### 3. **Output Progress Page** (Progress Bar)
```pascal
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:**
```pascal
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:**
```pascal
// After wpWelcome
MyPage := CreateInputQueryPage(wpWelcome, 'Title', 'Subtitle', 'Description');

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

---

### Validation and Logic

**Validate Before Next Page:**
```pascal
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:**
```pascal
function ShouldSkipPage(PageID: Integer): Boolean;
begin
  Result := False;

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

---

## Executing External Programs

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

### From Pascal Code
```pascal
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:**
```pascal
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:**
```pascal
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
```pascal
var
  UserName: String;

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

### Setting Environment Variables (Windows API Call)
```pascal
// 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
```pascal
SaveStringToFile(FileName, Content, Append)

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

### Load File to String
```pascal
var
  Content: String;

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

### Delete File
```pascal
DeleteFile('C:\temp\file.txt');
```

### File Exists Check
```pascal
if FileExists('C:\MyApp\config.ini') then
  MsgBox('Config found!', mbInformation, MB_OK);
```

### Directory Exists Check
```pascal
if DirExists('C:\MyApp') then
  MsgBox('Directory exists!', mbInformation, MB_OK);
```

---

## Common Pascal Script Functions

### Message Boxes
```pascal
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
```pascal
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
```pascal
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
```pascal
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
```bash
# 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
```batch
@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
```bash
cd ~/projects/inno
mkdir MyNewProject
cd MyNewProject
```

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

### 3. Edit Basic Settings
```pascal
[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
```pascal
[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
```bash
# 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
```pascal
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
```pascal
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
```pascal
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
```pascal
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]`:
```pascal
[Setup]
OutputDebugString=yes
```

### View Installer Log
Run installer with `/LOG`:
```cmd
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
```cmd
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
```cmd
MyInstaller.exe /VERYSILENT /NORESTART /LOG="C:\install.log"
```

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

---

## Reference Links

- **Official Documentation**: https://jrsoftware.org/ishelp/
- **Pascal Scripting**: https://jrsoftware.org/ishelp/index.php?topic=scriptintro
- **Example Scripts**: https://jrsoftware.org/ishelp/index.php?topic=scriptexamples
- **Command Line Parameters**: https://jrsoftware.org/ishelp/index.php?topic=setupcmdline
- **Download Inno Setup**: https://jrsoftware.org/isdl.php

---

## 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
