Launching App from Inno Setup so that setup process closes - inno-setup

What is the procedure to run/launch an application after a silent setup, so that the Setup installer closes and returns the exit code?
I need this behavior for launcher scripts to detect if setup passed/failed, while the end-user may start to use the app already.

Use nowait flag:
[Run]
Filename: "{app}\check.exe"; Flags: nowait

Related

Elegantly using try / catch with dotnet constants in Inno [Run] section [duplicate]

I have a .NET DLL. It can be registered by RegAsm .NET 3.5 and .NET 4.5.
I use this codes in my setup script:
[Run]
Filename: "{dotnet40}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet4064}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet20}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
Filename: "{dotnet2064}\RegAsm.exe"; Parameters: "my.dll"; WorkingDir: "{app}"; Flags: skipifdoesntexist; StatusMsg: "Registering Controls."
It works well if .NET 3.5 and .NET 4.5 is installed on the target machine
I have a function in my script to checking .net in InitializeSetup. So I know one of these versions are installed on the system: v3.5 v4 v4.5
But
we get error in some cases like this: if we have not .NET 3.5 on the target machine
I guess the error reason is:
{dotnet20}
.NET Framework version 2.0 root directory. {dotnet20} is equivalent to {dotnet2032} unless the install is running in 64-bit
mode, in which case it is equivalent to {dotnet2064}.
An exception will be raised if an attempt is made to expand this constant on a system with no .NET Framework version 2.0 present.
My question is how can I handle and ignore this exception and prevent setup rollback:
Internal error: .Net Framework version 2.0 not found.
If you want to stick to the [Run] section and do not write this in a scripting code, then I think you don't have many options to choose from. An exception is raised whenever a constant cannot be expanded, and that is just this case. The only option I can think of is adding a Check function that will attempt to expand the constant in a protected try..except block and prevent the entry to be processed when an exception is raised. Something like follows (based on your code, shortened):
[Run]
Filename: "{dotnet20}\RegAsm.exe"; Parameters: "File.dll"; Check: RegAsmDotNet20Exists
[Code]
function RegAsmDotNet20Exists: Boolean;
begin
try
// process the entry only if the target binary could be found (and so the
// folder constant could have been properly expanded)
Result := FileExists(ExpandConstant('{dotnet20}\RegAsm.exe'));
except
// this is the fallback in case the folder constant could not be expanded,
// or something unexpected happened when checking if the binary file to be
// executed exists; in such case, don't process the entry
Result := False;
end;
end;
Another, quite cleaner and a bit safer option would be doing your assembly registration purely from [Code] section in some of the postinstall events. Even though you'd still need to catch exceptions when using those constants, you would get more control over that tool (e.g. you could get the exit code to obtain an error reason if that tool uses it).

Run File One After The Other

I'm trying to install a couple executable files from the run section within an inno setup file.My File Section looks like this.
[Run]
#if GNTCChecked == "True"
Filename: "{tmp}\Utilities\SDK\setup.exe"; Description: "Install Foo"; Flags: nowait postinstall shellexec
Filename: "{tmp}\Utilities\SDK\foobar.exe"; Description: "Install Foo Update";
Flags: nowait postinstall shellexec
#endif
The 1st file needs to be installed in order for 2nd file to install.Basically if the first file is not installed, the 2nd will throw an error explaining that the core files are not on the system and therefore cant be installed.At the moment, the first file is executing, and the 2nd one straight after it before the 1st one has completed installing.
Here is what I had to do in order to execute one file after the other only when the first task had completed.
[Run]
#if GNTCChecked == "True"
Filename: "{tmp}\Utilities\SDK\setup.exe"; Description: "Install Foo";
Flags: postinstall shellexec waituntilterminated
Filename: "{tmp}\Utilities\SDK\foobar.exe"; Description: "Install Foo Update";
Flags: postinstall
#endif
Here was the information that I read that lead me to the answer.
shellexec
This flag is required if Filename is not a directly executable file (an .exe or .com file). When this flag is set, Filename can be a folder or any registered file type -- including .chm, .doc, and so on. The file will be opened with the application associated with the file type on the user's system, the same way it would be if the user double-clicked the file in Explorer.
By default, when the shellexec flag is used it will not wait until the spawned process terminates. If you need that, you must add the flag waituntilterminated. Note that it cannot and will not wait if a new process isn't spawned -- for example, if Filename specifies a folder.

Installing MS SQL Server Express 2017 with Inno Installer

I'm desperately trying to install SQL Server Express 2017 with Inno Installer.
Within my installer I include the extracted installer files.
That means that I already executed the common SQLEXPR_x64_ENU.exe, to avoid the "extract-temp-folder" prompt while my installer is running.
I execute the following on the cmd:
{somePath}\SQLEXPR_x64_ENU\setup.exe /ACTION=Install /Q /SKIPRULES=RebootRequiredCheck /SUPPRESSPRIVACYSTATEMENTNOTICE=1 /IAcceptSQLServerLicenseTerms=1 /SECURITYMODE=SQL /SAPWD=secretPW /ConfigurationFile=ConfigurationFileExpr.ini
The install succeeds.
But when I do the same within my InnoInstaller-File like this:
...
[Files]
Source: "SQLEXPR_x64_ENU\*"; DestDir: "{tmp}\SQLEXPR_x64_ENU"; Check: not SQLExpress_Check; Flags: recursesubdirs;
[Run]
Filename: "{tmp}\SQLEXPR_x64_ENU\setup.exe"; Description: "Installing SQL Server Express 2017..."; StatusMsg: "Installing SQL Server Express 2017..."; \
Parameters: "/ACTION=Install /Q /SKIPRULES=RebootRequiredCheck /SUPPRESSPRIVACYSTATEMENTNOTICE=1 /IAcceptSQLServerLicenseTerms=1 /SECURITYMODE=SQL /SAPWD=secretPW /ConfigurationFile=ConfigurationFileExpr.ini"; Check: not SQLExpress_Check; Flags: runascurrentuser;
...
SQL Installer fails with the following error:
Exception type: System.MissingMethodException
Message:
Method not found: 'Void Microsoft.SqlServer.Chainer.Infrastructure.RoleService.Initialize(Microsoft.SQL.Chainer.Product.RolesType)'.
HResult : 0x80131513
Data:
DisableWatson = true
Stack:
at Microsoft.SqlServer.Configuration.BootstrapExtension.InitializeRoleServiceAction.ExecuteAction(String actionId)
at Microsoft.SqlServer.Chainer.Infrastructure.Action.Execute(String actionId, TextWriter errorStream)
at Microsoft.SqlServer.Setup.Chainer.Workflow.ActionInvocation.<>c__DisplayClasse.<ExecuteActionWithRetryHelper>b__b()
at Microsoft.SqlServer.Setup.Chainer.Workflow.ActionInvocation.ExecuteActionHelper(ActionWorker workerDelegate)
Is this a permission error?
I do not have a clue.
On cmd-shell it works, but not on InnoInstaller.
Thanks in advance for your efforts and have a nice day.
Solution for me was provided by Gavin Lambert on the Inno Setup Forum :
If you're [installing from the directory of unpacked files], you need to use {sd}\shortname as the DestDir (usually combined with deleteafterinstall) -- you can't put the files in {tmp} or any similar path as the files are very deeply nested and the db installer ends up failing to access some files because the path is too long.
If you use an unpacked installer file, here is what should work absolutely perfect.
SQLEXPR_x64_ENU.exe /x:%temp%\SQLEXPR_x64_ENU\ /QS /ACTION=Install /SKIPRULES=RebootRequiredCheck /SUPPRESSPRIVACYSTATEMENTNOTICE=1 /IAcceptSQLServerLicenseTerms=1 /SECURITYMODE=SQL /SAPWD=secretPW /ConfigurationFile=ConfigurationFileExpr.ini
In the above command, /x:%temp%\SQLEXPR_x64_ENU\ is the very important switch where it describes the extraction location and with combination to /QS it will show you the progress on screen but will not ask for any input.
You may have to change %temp% to appropriate command to grab a windows temporary folder in your installer. The command I have posted is good for command-line execution.
Enjoy! :)

Inno Setup desktop shortcut (link) which has "Run as administrator" advanced property set

I am struggling to get Inno setup (5.5.9u) to created a desktop shortcut that has an icon and has the advanced property of "Run as administrator" set.
Issue
This question, is a little different than: How to set 'Run as administrator' on a file using Inno Setup
Since what I am trying to do is not run a program at setup time with admin rights, (setup is already running at Admin), but rather leave a link on the desktop that has has the advanced property of "Run as Administrator".
Code Sample
[Icons]
Name: "{group}\EGPL Watson Uninstall"; Filename: "{uninstallexe}"; \
WorkingDir: "{app}"
Name: "{commondesktop}\DashBoard"; \
Filename: "{app}\dashboard\node_modules\electron\dist\electron.exe main.js"; \
WorkingDir: "{app}\dashboard"; \
IconFilename: "{src}\dashboard\build\configure.ico"
First, make sure you have a very good reason to run your application with Administrator privileges. User applications should not need Administrator privileges. If they need it, it's usually a sign of a bad design. One common (bad) reason to want an application to run with Administrator privileges, is that the application needs to write to its installation folder.
See Application does not work when installed with Inno Setup
Inno Setup does not natively support creating a shortcut with "Run as Administrator" flag set.
The "Run as Administrator" flag is a bit the .lnk file. See:
LinkFlags in [MS-SHLLINK]: Shell Link (.LNK) Binary File Format;
How to create a Run As Administrator shortcut using Powershell
How can I use JScript to create a shortcut that uses "Run as Administrator"
You can set the bit using the following code:
[Icons]
Name: "{userdesktop}\My Program"; Filename: "{app}\MyProg.exe"; \
AfterInstall: SetElevationBit('{userdesktop}\My Program.lnk')
[Code]
procedure SetElevationBit(Filename: string);
var
Buffer: string;
Stream: TStream;
begin
Filename := ExpandConstant(Filename);
Log('Setting elevation bit for ' + Filename);
Stream := TFileStream.Create(FileName, fmOpenReadWrite);
try
Stream.Seek(21, soFromBeginning);
SetLength(Buffer, 1);
Stream.ReadBuffer(Buffer, 1);
Buffer[1] := Chr(Ord(Buffer[1]) or $20);
Stream.Seek(-1, soFromCurrent);
Stream.WriteBuffer(Buffer, 1);
finally
Stream.Free;
end;
end;
Tested on Unicode version of Inno Setup (the only version as of Inno Setup 6). But it should, even more naturally, work on Ansi version too.

Inno Setup: How to run a code procedure in Run section or before Run section?

I want to remove the old database before installing the new one, to update it for the user.
I have the following scenario:
In my Components section I have an option for the user:
[Components]
Name: "updateDatabase"; Description: "Update Database"; Types: custom; \
Flags: checkablealone disablenouninstallwarning
And I have in Code section, a procedure to execute, if the user selects this option, in the run section, before installing the new one.
[Code]
procedure RemoveOldDatabase();
begin
...
end;
[Run]
**--> Here I want to call RemoveOldDatabase if Components: updateDatabase is checked**
Filename: "database.exe"; StatusMsg: "Installing new database..."; Components: updateDatabase
The installation of the new database works fine. The problem is I want to remove the old one before installing the new one, calling the procedure RemoveOldDatabase.
Is it possible by only using Inno Setup?
Thanks.
One way, in my view really simple and still descriptive, is to execute your procedure as a BeforeInstall parameter function of your [Run] section entry. A BeforeInstall parameter function is executed once right before an entry is processed (and only if it's processed, which in your case is when the component is selected). You would write just this:
[Run]
Filename: "database.exe"; Components: UpdateDatabase; BeforeInstall: RemoveOldDatabase
[Code]
procedure RemoveOldDatabase;
begin
{ ... }
end;

Resources