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>
1047 lines
28 KiB
Markdown
1047 lines
28 KiB
Markdown
# 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
|