How to show user if installer is installing or upgrading [duplicate] - inno-setup

This question already has answers here:
Inno Setup: How to automatically uninstall previous installed version?
(13 answers)
Closed 1 year ago.
How do I detect whether the user already installed the software and if so, how to offer the possibility of removing the old version?
I have written some lines to check that. Is that correct for now? If this is correct, then how can I let the user choose whether he wants to continue the installation or uninstall the old version?
#define UNINSTKEY "Software\Microsoft\Windows\CurrentVersion\Uninstall\setupname_is1"
var
uninstallPath: string;
function InitializeSetup: Boolean;
begin
if (RegQueryStringValue(HKLM,'{#UNINSTKEY}','UninstallString',uninstallPath)) and
(uninstallPath <> '') and (fileexists(uninstallPath)) then
begin
Result :=
(MsgBox(CustomMessage('NotVerifiedVersionFound'), mbConfirmation,
MB_YESNO or MB_DEFBUTTON2) = IDYES);
end;
{ ... }
end;

You could use Craig McQueen's solution originally posted here: InnoSetup: How to automatically uninstall previous installed version?
function GetUninstallString: string;
var
sUnInstPath: string;
sUnInstallString: String;
begin
Result := '';
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{A227028A-40D7-4695-8BA9-41DF6A3895C7}_is1'); { Your App GUID/ID }
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
function IsUpgrade: Boolean;
begin
Result := (GetUninstallString() <> '');
end;
function InitializeSetup: Boolean;
var
V: Integer;
iResultCode: Integer;
sUnInstallString: string;
begin
Result := True; { in case when no previous version is found }
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{A227028A-40D7-4695-8BA9-41DF6A3895C7}_is1', 'UninstallString') then { Your App GUID/ID }
begin
V := MsgBox(ExpandConstant('Hey! An old version of app was detected. Do you want to uninstall it?'), mbInformation, MB_YESNO); { Custom Message if App installed }
if V = IDYES then
begin
sUnInstallString := GetUninstallString();
sUnInstallString := RemoveQuotes(sUnInstallString);
Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
Result := True; { if you want to proceed after uninstall }
{ Exit; //if you want to quit after uninstall }
end
else
Result := False; { when older version present and not uninstalled }
end;
end;

For anyone interested, I wrote a small DLL for Inno Setup 6 and newer that provides the ability to detect if an application is installed and to automatically uninstall the previous installed version based on your own criteria.
https://github.com/Bill-Stewart/UninsIS
Using the DLL you can automatically uninstall only when downgrading, only when upgrading, or either.

Related

Update an InnoSetup Installation - Update Previous Install Dir

I am creating installers for either full application and patch.
For the full app installer (300MB+), versioning is x.x.0 (ex. 1.1.0).
And for the patch (10MB+) it is x.x.x (ex. 1.1.1).
The installation folder is formatted like this: "App Name ".
Example - App Name 1.1.0, App Name 1.1.1
There should only be 1 version of the app that resides in the machine, so for full version installs - when the app is detected to be previously installed, the existing app is uninstalled first.
So the scenario is like this:
User installs a full app - 1.1.0 (OK)
Directory App Name 1.1.0 is created
User installs a patch - 1.1.1 (OK)
UsePreviousAppDir=true so it writes on top of directory App Name 1.1.0
App Name 1.1.0 is renamed to App Name 1.1.1 as part of CurStepChanged() when CurStep is ssPostInstall.
User installs a full app - 1.2.0 (NOK - expected to uninstall the prev version 1.1.1 and install this new version 1.2.0)
If UsePreviousAppDir is true, directory App Name 1.1.0 is created. This is because this is what Innosetup remembers as the "previous app" (since we only renamed the patch).
If UsePreviousAppDir is false, directory App Name 1.2.0 is created. And the prev version App Name 1.1.1 is not uninstalled because the previous install was pointing to App Name 1.1.0.
How can I configure my ISS file so that when I do a full install after a patch install, it can still find the renamed directory and uninstall it?
For reference, here is my code for renaming in patch installer:
{ ///////////////////////////////////////////////////////////////////// }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssPostInstall) then begin
RenameFile(ExpandConstant('{app}'), ExpandConstant('{app}\..\{#MyAppName} {#MyAppVersion}'))
end;
end;
And for my uninstall script (full version):
{ ///////////////////////////////////////////////////////////////////// }
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{#emit SetupSetting("AppId")}_is1');
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
{ ///////////////////////////////////////////////////////////////////// }
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
{ ///////////////////////////////////////////////////////////////////// }
function UnInstallOldVersion(): Integer;
var
sUnInstallString: String;
iResultCode: Integer;
begin
{ Return Values: }
{ 1 - uninstall string is empty }
{ 2 - error executing the UnInstallString }
{ 3 - successfully executed the UnInstallString }
{ default return value }
Result := 0;
{ get the uninstall string of the old app }
sUnInstallString := GetUninstallString();
if sUnInstallString <> '' then begin
sUnInstallString := RemoveQuotes(sUnInstallString);
if Exec(sUnInstallString, '/SILENT /NORESTART /SUPPRESSMSGBOXES','', SW_HIDE, ewWaitUntilTerminated, iResultCode) then
Result := 3
else
Result := 2;
end else
Result := 1;
end;
{ ///////////////////////////////////////////////////////////////////// }
procedure CurStepChanged(CurStep: TSetupStep);
begin
if (CurStep=ssInstall) then
begin
if (IsUpgrade()) then
begin
UnInstallOldVersion();
end;
end;
end;
And my [UninstallDelete] section in the patch installer, in case user wants to uninstall the entire thing:
[UninstallDelete]
Type: filesandordirs; Name: "{app}\..\{#MyAppName} {#MyAppVersion}"
Thanks!

Inno Setup check version of external application

What I'm trying to achieve is to check if Node.js is already is installed, and if so I wanna check for the version being up to date, let's say 8.x.x
From the question below I already achieved the initial check for it being installed at all. My Code looks pretty similar to the answer of the question.
Using Process Exit code to show error message for a specific File in [Run]
Now I'm struggling with reading the actual output of the node -v command (Expected result a string containing the version).
Is there a way to achieve that?
Running an application and parsing its output is rather inefficient way to check, if it exists and its version. Use FileSearch (node.exe is added to PATH) and GetVersionNumbers functions instead.
[Code]
function CheckNodeJs(var Message: string): Boolean;
var
NodeFileName: string;
NodeMS, NodeLS: Cardinal;
NodeMajorVersion, NodeMinorVersion: Cardinal;
begin
{ Search for node.exe in paths listed in PATH environment variable }
NodeFileName := FileSearch('node.exe', GetEnv('PATH'));
Result := (NodeFileName <> '');
if not Result then
begin
Message := 'Node.js not installed.';
end
else
begin
Log(Format('Found Node.js path %s', [NodeFileName]));
Result := GetVersionNumbers(NodeFileName, NodeMS, NodeLS);
if not Result then
begin
Message := Format('Cannot read Node.js version from %s', [NodeFileName]);
end
else
begin
{ NodeMS is 32-bit integer with high 16 bits holding major version and }
{ low 16 bits holding minor version }
{ shift 16 bits to the right to get major version }
NodeMajorVersion := NodeMS shr 16;
{ select only low 16 bits }
NodeMinorVersion := NodeMS and $FFFF;
Log(Format('Node.js version is %d.%d', [NodeMajorVersion, NodeMinorVersion]));
Result := (NodeMajorVersion >= 8);
if not Result then
begin
Message := 'Node.js is too old';
end
else
begin
Log('Node.js is up to date');
end;
end;
end;
end;
function InitializeSetup(): Boolean;
var
Message: string;
begin
Result := True;
if not CheckNodeJs(Message) then
begin
MsgBox(Message, mbError, MB_OK);
Result := False;
end;
end;
Since Inno Setup 6.1, you can use GetVersionComponents instead of GetVersionNumbers to avoid the bit magics.
For a similar question, see Checking if Chrome is installed and is of specific version using Inno Setup.

How to change the downloadpath in InnoSetup?

I want to download and install the .net framework 4.5 with silent installation in innosetup,using below condition i will check whether .netframework 4.5 available or not, if not i will download from web using shellexec. here i attached the code.
function Framework45IsNotInstalled: Boolean;
var
bVer4x5: Boolean;
bSuccess: Boolean;
iInstalled: Cardinal;
strVersion: String;
iPos: Cardinal;
ErrorCode: Integer;
begin
Result := True;
bVer4x5 := False;
bSuccess := RegQueryDWordValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Install', iInstalled);
if (1 = iInstalled) AND (True = bSuccess) then
begin
bSuccess := RegQueryStringValue(HKLM, 'Software\Microsoft\NET Framework Setup\NDP\v4\Full', 'Version', strVersion);
if (True = bSuccess) then
Begin
iPos := Pos('4.5.', strVersion);
if (0 < iPos) then bVer4x5 := True;
End
end;
if (True = bVer4x5) then begin
Result := False;
end;
ShellExec('', 'http://go.microsoft.com/fwlink/?LinkId=225702','{app}', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
Now my doubt is,while starting the download it opens the web browser, and it doesn't install the .net framework automatically, user need to install manually,i want innosetup to install automatically after download is happening, installation should happen in silent manner.Can i get any idea to achieve this task??
When using ShellExec() to tell the default browser to download something, then you have no control over what it does.
If you want to be able to run it afterwards, you will need to use an integrated downloader like InnoTools Downloader, or just ask the user to run it the install.

Uninstall when running inno setup with application already installed

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

uninstaller is not created after version upgrade

I have setup my installer to use the code referred to in this post to check for an existing version and then calling uninstall on it before installing the new version. Works great. My problem is that after the uninstall / install steps the new versions uninstall (unins000.exe) is not created (or maybe it was but is deleted IDK). This prevents the new version from being uninstalled properly later. The uninstaller is always created if there isn't an existing version. What am I doing wrong?
You could use Craig McQueen's solution originally posted here: InnoSetup: How to automatically uninstall previous installed version?
function GetUninstallString(): String;
var
sUnInstPath: String;
sUnInstallString: String;
begin
sUnInstPath := ExpandConstant('Software\Microsoft\Windows\CurrentVersion\Uninstall\{{A227028A-40D7-4695-8BA9-41DF6A3895C7}_is1'); //Your App GUID/ID
sUnInstallString := '';
if not RegQueryStringValue(HKLM, sUnInstPath, 'UninstallString', sUnInstallString) then
RegQueryStringValue(HKCU, sUnInstPath, 'UninstallString', sUnInstallString);
Result := sUnInstallString;
end;
function IsUpgrade(): Boolean;
begin
Result := (GetUninstallString() <> '');
end;
function InitializeSetup: Boolean;
var
V: Integer;
iResultCode: Integer;
sUnInstallString: String;
begin
if RegValueExists(HKEY_LOCAL_MACHINE,'Software\Microsoft\Windows\CurrentVersion\Uninstall\{A227028A-40D7-4695-8BA9-41DF6A3895C7}_is1', 'UninstallString') then begin
//Your App GUID/ID
V := MsgBox(ExpandConstant('{cm:YesNoUninstall}'), mbInformation, MB_YESNO); //Custom Message if App installed
if V = IDYES then begin
sUnInstallString := GetUninstallString();
sUnInstallString := RemoveQuotes(sUnInstallString);
Exec(ExpandConstant(sUnInstallString), '', '', SW_SHOW, ewWaitUntilTerminated, iResultCode);
Result := True; //if you want to proceed after uninstall
//Exit; //if you want to quit after uninstall
end
else begin
Result := False; //when older version present and not uninstalled
end;
end
else begin
Result := True; //when no previous version found
end;
end;

Resources