We prepare installers using Inno Setup. So a user installs the software. When new version is released, a new installer updates the software. So far so good.
But some people want to have both old version of the software and new one.
Is it possible to make an installer ask if a user wants to update current installation or install new version side by side.
In InitializeSetup event function, detect if the application is installed already. If it is, ask user, and if he/she chooses to install a new copy, change AppId and DefaultDirName to version-specific values to force a new installation.
[Setup]
#define AppId "My Program"
#define SetupReg "Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
#define DisplayVersionReg "DisplayVersion"
#define ApplicationVersion() \
ParseVersion('MyProg.exe', Local[0], Local[1], Local[2], Local[3]), \
Str(Local[0]) + "." + Str(Local[1])
[Setup]
AppId={code:GetAppId}
AppName=My Program
AppVersion={#ApplicationVersion}
DefaultDirName={code:GetDefaultDirName}
UsePreviousLanguage=no
[Files]
Source: "MyProg.exe"; DestDir: "{app}"
[Code]
var
AppId: string;
DefaultDirName: string;
function GetAppId(Param: string): string;
begin
Result := AppId;
Log('AppId = ' + Result);
end;
function GetDefaultDirName(Param: string): string;
begin
Result := DefaultDirName;
Log('DefaultDirName = ' + Result);
end;
function InitializeSetup(): Boolean;
var
PrevVersion: string;
CurVersion: string;
Message: string;
R: Integer;
begin
CurVersion := '{#ApplicationVersion}';
Log(Format('Installing "%s"', [CurVersion]));
Result := True;
AppId := '{#AppId}';
DefaultDirName := ExpandConstant('{pf}\My Program');
if RegQueryStringValue(HKLM, '{#SetupReg}', '{#DisplayVersionReg}', PrevVersion) or
RegQueryStringValue(HKCU, '{#SetupReg}', '{#DisplayVersionReg}', PrevVersion) then
begin
Message :=
Format(
'Version is %s already installed. Do you want to upgrade to %s?'#13#10#13#10+
'Press Yes, to replace %0:s with %1:s.'#13#10+
'Press No, to keep %0:s and add separate installation of %1:s.'#13#10, [
PrevVersion, CurVersion]);
R := MsgBox(Message, mbConfirmation, MB_YESNOCANCEL);
if R = IDYES then
begin
Log('User chose to replace previous installation');
end
else
if R = IDNO then
begin
AppId := AppId + CurVersion;
DefaultDirName := DefaultDirName + ' ' + CurVersion;
Log('User chose to install new copy - using ID ' + AppId);
end
else
begin
Log('User chose to cancel installation');
Result := False;
end;
end;
end;
Related
In my Inno Setup project, I download all files from the server and also download a file that has a version number. Now I want to read the version from the file and assign it to [Setup] section AppVersion in the Code section. My question is that possible to set the app version in the Code section?
Combining these two questions:
How to set version number from Inno Setup Pascal Script
Inno Setup - HTTP request - Get www/web content
[Setup]
AppVersion={code:GetAppVersion}
[Code]
var
Version: string;
function GetAppVersion(Param: string): string;
var
WinHttpReq: Variant;
begin
if Version = '' then
begin
WinHttpReq := CreateOleObject('WinHttp.WinHttpRequest.5.1');
WinHttpReq.Open('GET', 'https://www.example.com/version.txt', False);
WinHttpReq.Send('');
if WinHttpReq.Status <> 200 then
begin
Log('HTTP Error: ' + IntToStr(WinHttpReq.Status) + ' ' + WinHttpReq.StatusText);
MsgBox('Cannot obtain version', mbError, MB_OK);
Abort();
end
else
begin
Version := Trim(WinHttpReq.ResponseText);
Log('Version: ' + Version);
// you may want to validate that the value is meaningful here
end;
end;
Result := Version;
end;
My Inno Setup script is used to install a driver. It runs my InstallDriver.exe after this file was copied during step ssInstall.
I need to ask the user to restart in some cases according to the value returned by InstallDriver.exe.
This means that I cannot put InstallDriver.exe in section [Run] because there's no way to monitor it's return value.
So I put it in function CurStepChanged() as follows:
procedure CurStepChanged(CurStep: TSetupStep);
var
TmpFileName, ExecStdout, msg: string;
ResultCode: Integer;
begin
if (CurStep=ssPostInstall) then
begin
Log('CurStepChanged(ssPostInstall)');
TmpFileName := ExpandConstant('{app}') + '\InstallDriver.exe';
if Exec(TmpFileName, 'I', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then .......
However, I can't find a way to make my script restart at this stage.
I thought of using function NeedRestart() to monitor the output of the driver installer, but it is called earlier in the process.
Does it make sense to call the driver installer from within NeedRestart()?
NeedRestart does not look like the right place to install anything. But it would work, as it's fortunately called only once. You will probably want to present a progress somehow though, as the wizard form is almost empty during a call to NeedRestart.
An alternative is to use AfterInstall parameter of the InstallDriver.exe or the driver binary itself (whichever is installed later).
#define InstallDriverName "InstallDriver.exe"
[Files]
Source: "driver.sys"; DestDir: ".."
Source: "{#InstallDriverName}"; DestDir: "{app}"; AfterInstall: InstallDriver
[Code]
var
NeedRestartFlag: Boolean;
const
NeedRestartResultCode = 1;
procedure InstallDriver();
var
InstallDriverPath: string;
ResultCode: Integer;
begin
Log('Installing driver');
InstallDriverPath := ExpandConstant('{app}') + '\{#InstallDriverName}';
if not Exec(InstallDriverPath, 'I', '', SW_HIDE, ewWaitUntilTerminated, ResultCode) then
begin
Log('Failed to execute driver installation');
end
else
begin
Log(Format('Driver installation finished with code %d', [ResultCode]))
if ResultCode = NeedRestartResultCode then
begin
Log('Need to restart to finish driver installation');
NeedRestartFlag := True;
end;
end;
end;
function NeedRestart(): Boolean;
begin
if NeedRestartFlag then
begin
Log('Need restart');
Result := True;
end
else
begin
Log('Do not need restart');
Result := False;
end;
end;
This question already has an answer here:
Inno-setup 32bit and 64bit in one
(1 answer)
Closed 4 years ago.
I want to add vcredist_x64.exe and vcredist_x86.exe with my Inno Setup installer. How my installer will detect the OS whether it is 64bit or 32bit and it will install the file vcredist file as per OS.
Try this:
in the [Files] section add
Source: "vcredist_x86.exe"; DestDir: {tmp}; Flags: IgnoreVersion replacesameversion; Check: "not IsWin64";
Source: "vcredist_x64.exe"; DestDir: {tmp}; Flags: IgnoreVersion replacesameversion; Check:IsWin64;
and in your [Code] section do:
function Launch_VCRedist(svDir:String) : Boolean;
var
svTargetApplication: String;
svParameter: String;
workingDir: String;
showCmd: Integer;
wait: TExecWait;
resultCode: Integer;
VersionMS, VersionLS : Cardinal;
Major, Minor, Rev, Build: Cardinal;
Version:String;
begin
Result := True;
//Optional: if you want to execute silently your redist.exe, add this. This is for vc_redist version from 2005 to 2012
GetVersionNumbers(svDir + '\vcredist_x86.exe', VersionMS, VersionLS);
Major := VersionMS shr 16;
case Major of
11: //2012
begin
svParameter := '/install /passive';
end
10: //2010
begin
svParameter := '/passive /showfinalerror';
end
6: //2005
begin
svParameter := '/q';
end
9: //2008
begin
svParameter := '/Q';
end
end;
workingDir := '';
showCmd := SW_SHOW;
wait := ewWaitUntilTerminated;
retVal := Exec(svDir + '\vcredist_x86.exe', svParameter, workingDir, showCmd, wait, resultCode)
if retVal then
begin
//handle success if necessary; resultCode contains the exit code
end
else begin
//handle failure if necessary; resultCode contains the error code
Result := False;
end;
end;
And in CurStepChanged procedure add:
procedure CurStepChanged(CurStep: TSetupStep);
begin
case CurStep of
ssPostInstall:
b_ret := Launch_VCRedist(ExpandConstant('{tmp}'));
if b_ret Then
begin
//Handle success if necessary
end
else begin
//Handle failure if necessary
end;
end;
end;
I'm new to Inno, but want to check '{pf32}\Google\Drive\googledrivesync.exe' is installed before install.
However, the code does not pick up {pf32} as it does in Check: for a file.
New some can you assist please
Michael
[Code]
function InitializeSetup(): Boolean;
var FilePath3, FP1: String;
begin
//Result := FileExists(FilePath3);
//FP1:= {pf32} FilePath3:= '\Google\Drive\googledrivesync.exe'
if not FileExists({pf32} + FilePath3) Then
begin MsgBox({pf32} + FilePath3 + 'Google Drive not installed correctly - Setup will now exit - Please reinstall Google Drive!', mbError, MB_OK);
abort;
end;
end;
You have to use ExpandConstant in order to...well...expand constants. :-)
function InitializeSetup(): Boolean;
var
FilePath3: String;
PFDir: string;
begin
PFDir := ExpandConstant('{pf32}');
FilePath3:= '\Google\Drive\googledrivesync.exe'
Result := FileExists(PFDir + FilePath3);
if not Result then
begin
MsgBox(PFDir + FilePath3 + #13#13 +
'Google Drive not installed' +
'correctly - Setup will now exit.'#13 +
'Please reinstall Google Drive!', mbError, MB_OK);
Abort;
end;
end;
NOTE: I don't recall off-hand if ExpandConstant includes the trailing backslash or not, so you'll have to test. If so, you'll need to remove the backslash that starts FilePath3.
I have just started using inno setup, and it seems to work well. However, when I run the installer with the app already installed it reinstalls. I would like to give the user to uninstall. Is this possible, and if so, how can it be done?
To be specific, I have written a game for a homework assignment. I made an installer using inno setup. The app installs fine and can be uninstalled using the control panel, but my professor would like to be able to uninstall the application by re-running the installer and choosing an uninstall option. This will save him time since he has about 50 of these assignments to mark.
Thanks,
Gerry
The next script will make the following options form when the application is already installed on the target system when the setup is started:
When the user clicks Repair button, the setup is normally started. When user clicks the Uninstall button, the previously installed application is uninstalled. When user closes that form, nothing happens.
Here is the script (don't forget to specify, ideally some unique, value for the AppId setup directive in your script):
[Setup]
AppName=My Program
AppVersion=1.5
AppId=1C9FAC66-219F-445B-8863-20DEAF8BB5CC
DefaultDirName={pf}\My Program
OutputDir=userdocs:Inno Setup Examples Output
[CustomMessages]
OptionsFormCaption=Setup options...
RepairButtonCaption=Repair
UninstallButtonCaption=Uninstall
[Code]
const
mrRepair = 100;
mrUninstall = 101;
function ShowOptionsForm: TModalResult;
var
OptionsForm: TSetupForm;
RepairButton: TNewButton;
UninstallButton: TNewButton;
begin
Result := mrNone;
OptionsForm := CreateCustomForm;
try
OptionsForm.Width := 220;
OptionsForm.Caption := ExpandConstant('{cm:OptionsFormCaption}');
OptionsForm.Position := poScreenCenter;
RepairButton := TNewButton.Create(OptionsForm);
RepairButton.Parent := OptionsForm;
RepairButton.Left := 8;
RepairButton.Top := 8;
RepairButton.Width := OptionsForm.ClientWidth - 16;
RepairButton.Caption := ExpandConstant('{cm:RepairButtonCaption}');
RepairButton.ModalResult := mrRepair;
UninstallButton := TNewButton.Create(OptionsForm);
UninstallButton.Parent := OptionsForm;
UninstallButton.Left := 8;
UninstallButton.Top := RepairButton.Top + RepairButton.Height + 8;
UninstallButton.Width := OptionsForm.ClientWidth - 16;
UninstallButton.Caption := ExpandConstant('{cm:UninstallButtonCaption}');
UninstallButton.ModalResult := mrUninstall;
OptionsForm.ClientHeight := RepairButton.Height + UninstallButton.Height + 24;
Result := OptionsForm.ShowModal;
finally
OptionsForm.Free;
end;
end;
function GetUninstallerPath: string;
var
RegKey: string;
begin
Result := '';
RegKey := Format('%s\%s_is1', ['Software\Microsoft\Windows\CurrentVersion\Uninstall',
'{#emit SetupSetting("AppId")}']);
if not RegQueryStringValue(HKEY_LOCAL_MACHINE, RegKey, 'UninstallString', Result) then
RegQueryStringValue(HKEY_CURRENT_USER, RegKey, 'UninstallString', Result);
end;
function InitializeSetup: Boolean;
var
UninstPath: string;
ResultCode: Integer;
begin
Result := True;
UninstPath := RemoveQuotes(GetUninstallerPath);
if UninstPath <> '' then
begin
case ShowOptionsForm of
mrRepair: Result := True;
mrUninstall:
begin
Result := False;
if not Exec(UninstPath, '', '', SW_SHOW, ewNoWait, ResultCode) then
MsgBox(FmtMessage(SetupMessage(msgUninstallOpenError), [UninstPath]), mbError, MB_OK);
end;
else
Result := False;
end;
end;
end;
For some reason your code
RegKey := Format('%s\%s_is1', ['Software\Microsoft\Windows\CurrentVersion\Uninstall',
'{#emit SetupSetting("AppId")}']);
returned an extra { to the _is1 value. I didn't had the time to check why or where i was wrong in my implementation,
all i confirm is that my installer works with the
RegKey := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
alternate.
Hope it helps.
Thank you for the code sample.
When using Inno Setup, there's no reason to uninstall a previous version unless that version was installed by a different installer program. Otherwise upgrades are handled automatically.
Your answer is here :
InnoSetup: How to automatically uninstall previous installed version? previous-installed-version