Click here to Skip to main content
15,888,579 members
Articles / Programming Languages / SQL

Inno Setup Dependency Installer

Rate me:
Please Sign up or sign in to vote.
4.91/5 (191 votes)
7 Aug 2023CPOL2 min read 1.7M   24.9K   427   392
Download and install any dependency such as .NET, Visual C++ or SQL Server during your application's installation!
In this article, you will see installation, usage, integration, details, and dependencies of Inno Setup Dependency Installer.

Inno Setup Dependency Installer

Introduction

Inno Setup Dependency Installer can download and install any dependency such as .NET, Visual C++ or SQL Server during your application's installation. In addition, it is easy to add your own dependencies as well.

Installation and Usage

  1. Download and install Inno Setup 6.2+.
  2. Download the script from here or from the Github repository.
  3. Open the extracted ExampleSetup.iss file.
  4. Comment out dependency function calls inside InitializeSetup function to disable installing them:
    • Pascal
      Dependency_AddVC2013;   // installed in example setup
      //Dependency_AddVC2013; // commented out and not installed in example setup
  5. Modify other sections like [Setup] [Files] [Icons] as necessary.
  6. Build the setup using Inno Setup compiler.

Integration

You can also just include CodeDependencies.iss file into your setup and call the desired Dependency_Add functions (some may need defining their exe file path before the include):

Pascal
#define public Dependency_Path_NetCoreCheck "dependencies\"

#include "CodeDependencies.iss"

[Setup]
; ...

[Code]
function InitializeSetup: Boolean;
begin
  // add the dependencies you need
  Dependency_AddDotNet70;
  // ...

  Result := True;
end;

Details

You have two ways to distribute the dependency installers. By default, most dependencies will be downloaded from the official website. Another way is to pack the dependency into a single executable setup like so:

  • Include the dependency setup file by defining the source:

    Pascal
    Source: "dxwebsetup.exe"; Flags: dontcopy noencryption
  • Call ExtractTemporaryFile() before the corresponding Dependency_Add function:

    Pascal
    ExtractTemporaryFile('dxwebsetup.exe');

The dependencies are installed based on the system architecture. If you want to install 32-bit dependencies on a 64-bit system, you can force 32-bit mode like so:

Pascal
Dependency_ForceX86 := True;  // force 32-bit install of next dependencies
Dependency_AddVC2013;
Dependency_ForceX86 := False; // disable forced 32-bit install again

If you only deploy 32-bit binaries and dependencies, you can also instead just not define ArchitecturesInstallIn64BitMode in [Setup].

Dependencies

  • .NET
    • .NET Framework 3.5 Service Pack 1
    • .NET Framework 4.0
    • .NET Framework 4.5.2
    • .NET Framework 4.6.2
    • .NET Framework 4.7.2
    • .NET Framework 4.8.1
    • .NET Core 3.1 (Runtime, ASP.NET, Desktop)
    • .NET 5.0 (Runtime, ASP.NET, Desktop)
    • .NET 6.0 (Runtime, ASP.NET, Desktop)
    • .NET 7.0 (Runtime, ASP.NET, Desktop)
  • C++
    • Visual C++ 2005 Service Pack 1 Redistributable
    • Visual C++ 2008 Service Pack 1 Redistributable
    • Visual C++ 2010 Service Pack 1 Redistributable
    • Visual C++ 2012 Update 4 Redistributable
    • Visual C++ 2013 Update 5 Redistributable
    • Visual C++ 2015-2022 Redistributable
  • SQL
    • SQL Server 2008 R2 Service Pack 2 Express
    • SQL Server 2012 Service Pack 4 Express
    • SQL Server 2014 Service Pack 3 Express
    • SQL Server 2016 Service Pack 3 Express
    • SQL Server 2017 Express
    • SQL Server 2019 Express
    • SQL Server 2022 Express
  • Access
    • Access Database Engine 2010
    • Access Database Engine 2016
  • DirectX End-User Runtime
  • WebView2 Runtime

Credits

Thanks to the community for sharing many fixes and improvements. To contribute, please create a pull request.

This article was originally posted at https://github.com/DomGries/InnoDependencyInstaller

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Unknown
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
GeneralRe: WizardSmallImageFile Pin
Anthony Daly1-Sep-10 8:51
Anthony Daly1-Sep-10 8:51 
GeneralRe: WizardSmallImageFile Pin
Pascal Hubert1-Sep-10 8:57
Pascal Hubert1-Sep-10 8:57 
GeneralRe: WizardSmallImageFile Pin
Anthony Daly1-Sep-10 9:24
Anthony Daly1-Sep-10 9:24 
GeneralRe: WizardSmallImageFile Pin
Pascal Hubert1-Sep-10 9:27
Pascal Hubert1-Sep-10 9:27 
GeneralRe: WizardSmallImageFile Pin
sakethrao24-Sep-10 2:05
sakethrao24-Sep-10 2:05 
GeneralNew .NET Framework 4 (Full + Client) script here! [modified] Pin
Anthony Daly4-Jul-10 6:34
Anthony Daly4-Jul-10 6:34 
GeneralUpdated MSI 4.5 for 32 and 64-bit Pin
jtitley24-Jun-10 21:12
jtitley24-Jun-10 21:12 
GeneralSome Enhancements Pin
jtitley24-Jun-10 21:09
jtitley24-Jun-10 21:09 
Thought I would submit some enhancements to the product.iss file. With the latest version of InnoSetup the PrepareInstall function allows us to easily perform mid-Install reboots. With some minor changes to the product.iss file we can take advantage of this.

I added two new fields to the TProduct record to specify if the product must reboot after (Installer 4.5 requires this), or if the install requires a clean install (i.e. no pending reboots). For example .NET 4.0 requires a clean install, but .NET 3.5 SP1 does not. You do have to change all the product files to include these extract variables though.

The new function PendingReboot will detect if a reboot is pending by checking the registry for any queued up any executables or file renames. You can check for this at the start of your installation to ensure a clean install.

If a reboot is required, the install stops and then configures setup to be automatically re-run after reboot.

Note that I also changed error code 3010 to 0. This is MSI's way of reporting a delayed boot, but for my purposes I wanted to treat it as success.

One issue with this is that when prompted for a reboot, you can hit the back button. To get around this, I disabled it in my main install code.

function BackButtonClick(CurPageID: Integer): Boolean;
begin
   if (CurPageID = 11) then
       Result := false
      else
      Result := true;
end;



Here is the changed product.iss file:

#include "isxdl\isxdl.iss"

[CustomMessages]
DependenciesDir=MyProgramDependencies

en.depdownload_msg=The following applications are required before setup can continue:%n%n%1%nDownload and install now?
de.depdownload_msg=Die folgenden Programme werden benötigt bevor das Setup fortfahren kann:%n%n%1%nJetzt downloaden und installieren?

en.depdownload_memo_title=Download dependencies
de.depdownload_memo_title=Abhängigkeiten downloaden

en.depinstall_memo_title=Install dependencies
de.depinstall_memo_title=Abhängigkeiten installieren

en.depinstall_title=Installing dependencies
de.depinstall_title=Installiere Abhängigkeiten

en.depinstall_description=Please wait while Setup installs dependencies on your computer.
de.depinstall_description=Warten Sie bitte während Abhängigkeiten auf Ihrem Computer installiert wird.

en.depinstall_status=Installing %1...
de.depinstall_status=Installiere %1...

en.depinstall_missing=%1 must be installed before setup can continue. Please install %1 and run Setup again.
de.depinstall_missing=%1 muss installiert werden bevor das Setup fortfahren kann. Bitte installieren Sie %1 und starten Sie das Setup erneut.

en.depinstall_error=An error occured while installing the dependencies. Please restart the computer and run the setup again or install the following dependencies manually:%n
de.depinstall_error=Ein Fehler ist während der Installation der Abghängigkeiten aufgetreten. Bitte starten Sie den Computer neu und führen Sie das Setup erneut aus oder installieren Sie die folgenden Abhängigkeiten per Hand:%n

de.isxdl_langfile=german2.ini


[Files]
Source: "scripts\isxdl\german2.ini"; Flags: dontcopy

[Code]
type
	TProduct = record
		File: String;
		Title: String;
		Parameters: String;
		InstallClean : Boolean;
		MustRebootAfter : Boolean;
	end;
	
var
	installMemo, downloadMemo, downloadMessage: string;
	products: array of TProduct;
	DependencyPage: TOutputProgressWizardPage;
	
	rebootRequired : boolean;
	rebootMessage : string;

procedure AddProduct(FileName, Parameters, Title, Size, URL: string; InstallClean : Boolean; MustRebootAfter : Boolean);
var
	path: string;
	i: Integer;
begin
	installMemo := installMemo + '%1' + Title + #13;
	
	path := ExpandConstant('{src}{\}') + CustomMessage('DependenciesDir') + '\' + FileName;
	if not FileExists(path) then begin
	  path := ExpandConstant('{tmp}{\}') + FileName;
		
		isxdl_AddFile(URL, path);
		
		downloadMemo := downloadMemo + '%1' + Title + #13;
		downloadMessage := downloadMessage + '    ' + Title + ' (' + Size + ')' + #13;
	end;
	
	i := GetArrayLength(products);
	SetArrayLength(products, i + 1);
	products[i].File := path;
	products[i].Title := Title;
	products[i].Parameters := Parameters;
	products[i].InstallClean := InstallClean;
	products[i].MustRebootAfter := MustRebootAfter;
end;

function SmartExec(fileName, parameters : string; var ResultCode : Integer) : Boolean;
begin
  if (UpperCase(Copy(fileName,Length(fileName)-2,3)) <> 'EXE') then begin
    Result := ShellExec('', fileName, parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
  end else begin
    Result := Exec(fileName, parameters, '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
  end;
  // MSI Deferred boot code 3010 is a success
  if (ResultCode = 3010) then ResultCode := 0;
  end;

function PendingReboot : Boolean;
var	Names: String;
begin
  if (RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', Names)) then begin
      Result := true;
  end else if ((RegQueryMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'SetupExecute', Names)) and (Names <> ''))  then begin
		Result := true;
	end
	else begin
	  Result := false;
  end;		
end;

function InstallProducts: Boolean;
var
	ResultCode, i, productCount, finishCount: Integer;
begin
	Result := true;
	productCount := GetArrayLength(products);
		
	if productCount > 0 then begin
		DependencyPage := CreateOutputProgressPage(CustomMessage('depinstall_title'), CustomMessage('depinstall_description'));
		DependencyPage.Show;
		
		for i := 0 to productCount - 1 do begin		  
		  if ((products[i].InstallClean = true) and PendingReboot)  then
		  begin
		    rebootRequired := true;
		    rebootmessage := products[i].Title;
		    exit;
		  end;
		  
			DependencyPage.SetText(FmtMessage(CustomMessage('depinstall_status'), [products[i].Title]), '');
			DependencyPage.SetProgress(i, productCount);			
       		
      if SmartExec(products[i].File, products[i].Parameters, ResultCode) then begin
				//success; ResultCode contains the exit code
				if ResultCode = 0 then begin
					finishCount := finishCount + 1
					if (products[i].MustRebootAfter = true) then begin
					   rebootRequired := true;
					   rebootmessage := products[i].Title;
					    if not PendingReboot then begin
  					       RegWriteMultiStringValue(HKEY_LOCAL_MACHINE, 'SYSTEM\CurrentControlSet\Control\Session Manager', 'PendingFileRenameOperations', '');
              end;
              exit;
          end;
        end
				else begin
					Result := false;
					break;
				end;
			end else begin
				//failure; ResultCode contains the error code
				Result := false;
				break;
			end;
		end;
		
		//only leave not installed products for error message
		for i := 0 to productCount - finishCount - 1 do begin
			products[i] := products[i+finishCount];
		end;
		SetArrayLength(products, productCount - finishCount);
		
		DependencyPage.Hide;
	end;
end;

function PrepareToInstall(var NeedsRestart: Boolean): String;
var
	i: Integer;
	s: string;
begin
  if not InstallProducts() then begin
		s := CustomMessage('depinstall_error');
		
		for i := 0 to GetArrayLength(products) - 1 do begin
			s := s + #13 + '    ' + products[i].Title;
		end;
		
		Result := s;
	end
  else if (rebootrequired) then
	begin
	   Result := RebootMessage;
	   NeedsRestart := true;
	    RegWriteStringValue(HKEY_CURRENT_USER, 'SOFTWARE\Microsoft\Windows\CurrentVersion\RunOnce',
                           'InstallBootstrap', ExpandConstant('{srcexe}'));
	end;
end;


function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo, MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
	s: string;
begin
	if downloadMemo <> '' then
		s := s + CustomMessage('depdownload_memo_title') + ':' + NewLine + FmtMessage(downloadMemo, [Space]) + NewLine;
	if installMemo <> '' then
		s := s + CustomMessage('depinstall_memo_title') + ':' + NewLine + FmtMessage(installMemo, [Space]) + NewLine;

	s := s + MemoDirInfo + NewLine + NewLine + MemoGroupInfo
	
	if MemoTasksInfo <> '' then
		s := s + NewLine + NewLine + MemoTasksInfo;

	Result := s
end;

function ProductNextButtonClick(CurPageID: Integer): Boolean;
begin
	Result := true;

	if CurPageID = wpReady then begin

		if downloadMemo <> '' then begin
			//change isxdl language only if it is not english because isxdl default language is already english
			if ActiveLanguage() <> 'en' then begin
				ExtractTemporaryFile(CustomMessage('isxdl_langfile'));
				isxdl_SetOption('language', ExpandConstant('{tmp}{\}') + CustomMessage('isxdl_langfile'));
			end;
			//isxdl_SetOption('title', FmtMessage(SetupMessage(msgSetupWindowTitle), [CustomMessage('appname')]));
			
			if SuppressibleMsgBox(FmtMessage(CustomMessage('depdownload_msg'), [downloadMessage]), mbConfirmation, MB_YESNO, IDYES) = IDNO then
				Result := false
			else if isxdl_DownloadFiles(StrToInt(ExpandConstant('{wizardhwnd}'))) = 0 then
				Result := false;
		end;
	end;
end;

function IsX64: Boolean;
begin
	Result := Is64BitInstallMode and (ProcessorArchitecture = paX64);
end;

function IsIA64: Boolean;
begin
	Result := Is64BitInstallMode and (ProcessorArchitecture = paIA64);
end;

function GetURL(x86, x64, ia64: String): String;
begin
	if IsX64() and (x64 <> '') then
		Result := x64;
	if IsIA64() and (ia64 <> '') then
		Result := ia64;
	
	if Result = '' then
		Result := x86;
end;

QuestionRe: Some Enhancements [modified] Pin
daveaton20-Nov-10 13:44
daveaton20-Nov-10 13:44 
GeneralRe: Some Enhancements Pin
Rei Masi23-Feb-11 1:45
Rei Masi23-Feb-11 1:45 
GeneralSome new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Hovedsjef11-Jun-10 2:46
Hovedsjef11-Jun-10 2:46 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Ramsdal4220-Jul-10 4:04
Ramsdal4220-Jul-10 4:04 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Hovedsjef20-Jul-10 11:18
Hovedsjef20-Jul-10 11:18 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Mezofi14-Sep-10 3:28
Mezofi14-Sep-10 3:28 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Nick Olsen16-Nov-10 8:04
Nick Olsen16-Nov-10 8:04 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Rei Masi23-Feb-11 0:47
Rei Masi23-Feb-11 0:47 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Nick Olsen23-Feb-11 2:38
Nick Olsen23-Feb-11 2:38 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
Rei Masi23-Feb-11 3:05
Rei Masi23-Feb-11 3:05 
GeneralRe: Some new packages: SQL 2008 R2 Express, SQL 3.5 Compact, MSI 4.5 [modified]♦ Pin
HEMICRO21-May-11 6:46
HEMICRO21-May-11 6:46 
QuestionCompile Error in products.iss line 114 Pin
Claudio Barca5-Jun-10 8:19
Claudio Barca5-Jun-10 8:19 
AnswerRe: Compile Error in products.iss line 114 Pin
runeb14-Jun-10 11:51
runeb14-Jun-10 11:51 
AnswerRe: Compile Error in products.iss line 114 Pin
NoiadoX23-Nov-10 7:31
NoiadoX23-Nov-10 7:31 
QuestionHelp. Minimal Script for my application Pin
Daniel0198324-May-10 7:12
Daniel0198324-May-10 7:12 
Question.NET Framework 4.0 Client Profile Compatibility Pin
jonnys212330-Apr-10 17:43
jonnys212330-Apr-10 17:43 
AnswerRe: .NET Framework 4.0 Client Profile Compatibility Pin
Aussie ALF4-May-10 2:02
Aussie ALF4-May-10 2:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.