Archive

Posts Tagged ‘Inno Setup’

Inno Setup Overview

January 19th, 2010 Matt J. Wilson No comments

Based on a lot of the hits to this blog, it seems like a lot of people are simply trying to understand Inno Setup. I hope this blog post will be useful; I’m not going to refer to any code here as I believe the other examples on this blog should suffice, but here is a brief outline of Inno Setup and ISTool.

First, you probably want to download a copy of Inno Setup. Inno Setup is basically a great, free alternative to other packaging solutions (InstallShield, etc.). There is a graphical, wizard interface that will suffice for building some of the basics of your project, but if you aren’t a programmer you’ll still have difficulties.

This is where ISTool comes in. ISTool adds a graphical layer on top of Inno Setup that allows non-programmers to create almost any type of script they desire in an easy-to-use UI. Even though I know how to write scripts in Inno Setup, I still use ISTool to form the basis of almost all of my scripts.

Another huge advantage of ISTool? It allows you to implement a download component into Inno Setup, which makes it very straight forward to add files to be download from the internet during an installation (view a sample of using the isxdl.dll included with ISTool).

Still have questions? Feel free to contact me.

Categories: Programming Tags:

Another Inno Setup Example

December 9th, 2009 Matt J. Wilson No comments

I realize no one will be able to copy and paste this script to do exactly what they want, but I thought several of these items might be useful.

I developed another Inno Setup script that copies all files from a file share locally, runs a few installers (from a nested “Installers” directory that houses all the exe’s as you’ll see), sets some registry settings for an ODBC connection to a DBISAM database, and copies the .NET trust settings from a nested “Net Framework” folder, which allows me to set a “Full Trust” as needed for several applications. This setup essentially lets me put the “Net Framework” and an “Installers” folder on a disc with the EXE that this script generates, creating an easy to use install disc for setting up new workstations.

Here is the code, I hope someone finds a useful snippet or two:

#define MyAppName "Software"
#define MyAppVerName "Software Installation 2.0"
#define MyAppPublisher "My Company"

[Setup]
; NOTE: The value of AppId uniquely identifies this application.
; Do not use the same AppId value in installers for other applications.
; (To generate a new GUID, click Tools | Generate GUID inside the IDE.)
AppId={{4D2577F9-92D0-4E6F-83DB-D4009B55C678}
AppName={#MyAppName}
AppVerName={#MyAppVerName}
AppPublisher={#MyAppPublisher}
DefaultDirName={pf}\Company Programs
DisableDirPage=yes
DefaultGroupName=Company Programs
DisableProgramGroupPage=yes
OutputBaseFilename=Setup
SetupIconFile=Company_Icon.ico
Compression=lzma
SolidCompression=true
Uninstallable=false

[Files]
; Copy all the Company Programs files shared directory
Source: O:\Company Programs\*; DestDir: {app}; Flags: ignoreversion recursesubdirs createallsubdirs uninsremovereadonly
; Copy the "FullTrust" needed for the .NET Framework
Source: NET Framework\v1.1.4322\*; DestDir: C:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\CONFIG; Flags: ignoreversion recursesubdirs createallsubdirs uninsremovereadonly

[Run]
; Run all our installers (network drives, printers, DBISAM, Winzip, .NET Framework and the Service Pack) from the nested /Installers directory
Filename: {src}\Installers\MapDrives.bat; WorkingDir: {src}; StatusMsg: Mapping Network Drives
Filename: {src}\Installers\MapPrinters.bat; WorkingDir: {src}; StatusMsg: Mapping Network Printers
Filename: {src}\dbisam\424b1dbisamodbcstd.exe; WorkingDir: {src}; StatusMsg: Installing DBISAM
Filename: {src}\Installers\winzip81.exe; WorkingDir: {src}; StatusMsg: Installing WinZip
Filename: {src}\Installers\dotnetfx.exe; WorkingDir: {src}; StatusMsg: Installing .NET Framework
Filename: {src}\Installers\NDP1.1sp1-KB867460-X86.exe; WorkingDir: {src}; StatusMsg: Installing .NET Framework Update

[Registry]
; Create registry keys for ODBC connections for the database
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM 4 Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: PrivateDirectory; ValueType: string; ValueData: C:\Temp
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\ODBC Data Sources; ValueType: string; ValueName: DBISAM Local Tables; ValueData: DBISAM 4 ODBC Driver; Flags: createvalueifdoesntexist uninsdeletevalue
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: Driver; ValueType: string; ValueData: C:\WINDOWS\system32\dbodbc.dll
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: ConnectionType; ValueType: string; ValueData: Local
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemoteHostName; ValueType: string; ValueData:
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemoteIPAddress; ValueType: string; ValueData: 127.0.0.1
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemotePort; ValueType: string; ValueData: 12005
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemoteService; ValueType: string; ValueData:
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemoteCompression; ValueType: string; ValueData: 0
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: UID; ValueType: string; ValueData:
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: PWD; ValueType: string; ValueData:
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: RemoteReadAhead; ValueType: string; ValueData: 50
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: MRUDatabase1; ValueType: string; ValueData: Memory
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: MRUDatabase2; ValueType: string; ValueData: C:\DB_Config\Tables
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: CatalogName; ValueType: string; ValueData: C:\DBL_Config\Tables
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: ReadOnly; ValueType: string; ValueData: False
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: LockRetryCount; ValueType: string; ValueData: 15
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: LockWaitTime; ValueType: string; ValueData: 100
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: ForceBufferFlush; ValueType: string; ValueData: False
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: StrictChangeDetection; ValueType: string; ValueData: False
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: MRUPrivateDirectory1; ValueType: string; ValueData: C:\DOCUME~1\MyUserName\LOCALS~1\Temp\
Root: HKLM; SubKey: Software\ODBC\ODBC.INI\DBISAM Local Tables; Flags: createvalueifdoesntexist uninsdeletevalue; ValueName: PrivateDirectory; ValueType: string; ValueData: C:\DOCUME~1\MyUserName\LOCALS~1\Temp\
Categories: Programming Tags:

Packaging a .NET Deployment Project into a Single EXE

February 13th, 2009 Matt J. Wilson No comments

So you want to package your MSI and EXE into a single EXE for distribution?  There’s no way to do it using .NET, but Inno Setup is an excellent, free utility that will allow us to create a bootstrap utility.  You will also need to download the ISTool pack to utilize the isxdl.dll.

This tool will ensure the user has the proper .NET framework installed; if not, it will retrieve it from the Microsoft site and begin installing it for them.   It will also retrieve your EXE and MSI files from any web location you specify, allowing them to automatically download and install (or uninstall later) for the user.

Enough rambling, here’s the code to use and enjoy (please note my link to the .NET Framework and registry checking are for 2.0):

[_ISTool]
EnableISX=true

[Setup]
AppName=YourAppName
AppVerName=Your App Version 1.0.0
MinVersion=4.1,4.0
DefaultDirName={pf}\Your Default Directory
DefaultGroupName=Your Default Group Name
Compression=lzma
SolidCompression=true
OutputBaseFilename=Your Output File Name
DisableDirPage=true
DisableProgramGroupPage=true
DisableReadyPage=false
DisableReadyMemo=true

[Files]
Source: C:\Program Files\ISTool\isxdl.dll; Flags: dontcopy

[Messages]
WinVersionTooLowError=YourAppName requires Windows 2000, Windows XP or later.

[Icons]
Name: {group}\Uninstall YourAppName; Filename: {uninstallexe}

[Code]
var
dotnetRedistPath: string;
downloadNeeded: boolean;
dotNetNeeded: boolean;
memoDependenciesNeeded: string;
uninstaller: String;
ErrorCode: Integer;

procedure isxdl_AddFile(URL, Filename: PChar);
external 'isxdl_AddFile@files:isxdl.dll stdcall';
function isxdl_DownloadFiles(hWnd: Integer): Integer;
external 'isxdl_DownloadFiles@files:isxdl.dll stdcall';
function isxdl_SetOption(Option, Value: PChar): Integer;
external 'isxdl_SetOption@files:isxdl.dll stdcall';

const
dotnetRedistURL = 'http://download.microsoft.com/download/5/6/7/567758a3-759e-473e-bf8f-52154438565a/dotnetfx.exe';
const
exeURL = 'http://www.pathtoyoursite.com/setup.exe';
const
msiURL = 'http://www.pathtoyoursite.com/Installation.msi';

function InitializeSetup(): Boolean;

begin
Result := true;
dotNetNeeded := false;

if not FileExists(ExpandConstant('{tmp}\setup.exe')) or not FileExists(ExpandConstant('{tmp}\Installation.msi'))  then
begin
isxdl_AddFile(exeURL, ExpandConstant('{tmp}\setup.exe'));
isxdl_AddFile(msiURL, ExpandConstant('{tmp}\Installation.msi'));
downloadNeeded := true;
end

// See if the .NET Framework is already installed
if (not RegKeyExists(HKLM, 'Software\Microsoft\.NETFramework\policy\v2.0')) then begin
dotNetNeeded := true;
if (not IsAdminLoggedOn()) then begin
MsgBox('YourAppName needs the Microsoft .NET Framework to be installed by an Administrator', mbInformation, MB_OK);
Result := false;
end else begin
memoDependenciesNeeded := memoDependenciesNeeded + '      .NET Framework' ;
dotnetRedistPath := ExpandConstant('{src}\dotnetfx.exe');
if not FileExists(dotnetRedistPath) then begin
dotnetRedistPath := ExpandConstant('{tmp}\dotnetfx.exe');
if not FileExists(dotnetRedistPath) then begin
isxdl_AddFile(dotnetRedistURL, dotnetRedistPath);
downloadNeeded := true;
end;
end;
SetIniString('install', 'dotnetRedist', dotnetRedistPath, ExpandConstant('{tmp}\dep.ini'));
end;
end;

end;

function NextButtonClick(CurPage: Integer): Boolean;
var
hWnd: Integer;
ResultCode: Integer;

begin
Result := true;

if CurPage = wpReady then begin

hWnd := StrToInt(ExpandConstant('{wizardhwnd}'));

// don't try to init isxdl if it's not needed because it will error on < ie 3
if downloadNeeded then begin

isxdl_SetOption('label', 'Downloading YourAppName Components');
isxdl_SetOption('description', 'YourAppName needs to install some components. Please wait while Setup is downloading extra files to your computer.');
if isxdl_DownloadFiles(hWnd) = 0 then Result := false;
end;
if (Result = true) and (dotNetNeeded = true) then begin
if Exec(ExpandConstant(dotnetRedistPath), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then begin
// handle success if necessary; ResultCode contains the exit code
if not (ResultCode = 0) then begin
Result := false;
end;
end else begin
// handle failure if necessary; ResultCode contains the error code
Result := false;
end;
end;
FileCopy(ExpandConstant('{tmp}\Installation.msi'),  ExpandConstant('{app}\Installation.msi'), false);
FileCopy(ExpandConstant('{tmp}\setup.exe'),  ExpandConstant('{app}\setup.exe'), false);
end;
end;

function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
s: string;

begin
if memoDependenciesNeeded <> '' then s := s + 'Dependencies to install:' + NewLine + memoDependenciesNeeded + NewLine;
s := s + MemoDirInfo + NewLine + NewLine;

Result := s
end;

[Run]
Filename: msiexec.exe; Parameters: "/i ""{tmp}\Installation.msi "" /qb"

[UninstallRun]
Filename: msiexec.exe; Parameters: "/x ""{app}\Installation.msi "" /quiet"

Thanks to the various posts on the web that gave me the basic understanding of Inno Setup and allowed me to create this script.

Categories: Programming Tags: ,

Inno Setup – The setup files are corrupted. Please obtain a new copy of the program.

February 10th, 2009 Matt J. Wilson No comments

During some recent work using Inno Setup to create a bootstrap application, several workstations were presented with the following error:

error 

 After hours upon hours of Googling, I still couldn’t find a fix that worked for me.  Upon more carefully examining my script, I noticed I had left the following line in my ISS file:

UninstallDisplayIcon={app}\icon25x25.ico

The problem was due to the fact that I never included this file under the [Files] area as I simply had no intention of ever using the icon.

So for future reference (and in case someone stumbles upon this through Google), always ensure any file reference is valid.  Your compiler and development machines may not throw an error, but if you plan to distribute this to several workstations this error may rear its ugly head.

UPDATE:

After fixing this file, I was still noticing an error on the hosting site (although any EXE file downloaded from my website worked flawlessly).  It turns out Redhat and PHP often don’t play too well together in this regard and need a few settings tweaked in httpd.conf, you may need to disable the EnableMMAP and/or EnableSendfile options.

Categories: Programming Tags: