Inno Setup Script - running exe before installing - inno-setup

I wanna run an application before installing and I'm using this code on Inno Setup Script(Pascal):
function InitializeSetup():boolean;
var
ResultCode: integer;
begin
// Launch Notepad and wait for it to terminate
if ExecAsOriginalUser('{src}\MyFolder\Injector.exe', '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode) then
begin
// handle success if necessary; ResultCode contains the exit code
end
else begin
// handle failure if necessary; ResultCode contains the error code
end;
// Proceed Setup
Result := True;
end;
When I'm using "{win}\notepad.exe", It works but when I use "{src}\MyFolder\Injector.exe", Setup doesn't open my program and continues install.
Note : Injector has app.manifest which has 'requireAdministrator'. However this application should be run as administrator.
So what's wrong?

You need to use the ExpandConstant function when using values such as {src} in code.
However, InitializeSetup is also too early to run installation tasks. You should move this code into CurStepChanged(ssInstall).
Also, if it requires admin permissions it must be run with Exec, not ExecAsOriginalUser.

This May work for you... I believe that this problem is because of spaces in the entire path..that should overcome with double quoting the path...
Exec('cmd.exe','/c "'+ExpandConstant('{src}\MyFolder\Injector.exe')+'"', '',SW_SHOW,ewWaitUntilTerminated, ResultCode);
cheers..

Related

Hardcode startup switches into INNO Setup script and retrieve them in [code] in InnoIDE

When I compile and then run my Inno script, I want to parse hard coded command line switches. So, instead of running my script as c:\myInstall.exe /myswitch I want to run it via IDE and have this switch included at the start here
With this code, I want to retrieve this switch in ParamStr(x)
function MyParams(param: String): string;
begin
MsgBox(ParamStr(3), mbError, MB_OK);
Result := MyParameter;
end;
{Parameter Detection--end}
function InitializeSetup(): Boolean;
begin
MyParams('XXX');
end;
I found a tool, which does this for you - you can set DEBUG variables if you use
Inno Script Studio

Run application after click on the Finish button (not after install)

I have a setup for installing my application, and I need to run the application after successfully installing. I used postinstall to do this.
but it shows a checkbox and the user can uncheck it. I need to run the application without asking because of it kinda service which needs to runs at startup. if the user unchecked it he needs to restart the PC to launch.
So I can use the Filename: "{app}\myapp.exe" code without any flags in the Run section to launch the application but the problem is, It runs immediately after installing not after the finish button clicked.
The first issue is my application has an instruction window. it shows up at the launch so the setup window goes to the back. And the second issue is my application does not allow terminating unless uninstall becouse it need to run in the background. Setup waiting to process end to finish.
Is there any way to run the application after the finish button click in inno setup?
Simplifying the answer from Run Files and Programs according to custom checkboxes after clicking on Finish Button in Inno Setup, you can use a code like this:
[Code]
function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
Path, Msg: string;
begin
if CurPageID = wpFinished then
begin
Path := ExpandConstant('{app}\MyProg.exe');
if ExecAsOriginalUser(Path, '', '', SW_SHOW, ewNoWait, ResultCode) then
begin
Log('Executed MyProg');
end
else
begin
Msg := 'Error executing MyProg - ' + SysErrorMessage(ResultCode);
MsgBox(Msg, mbError, MB_OK);
end;
end;
Result := True;
end;
Replace ExecAsOriginalUser with Exec, if you want to run the program with elevated/Administrator privileges (if the installer uses them at all).
Add code section to your script like this:
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
ResultCode: Integer;
begin
if CurStep = ssDone then
Exec(ExpandConstant('{app}\MyProg.exe'), '', '', SW_SHOW, ewNoWait, ResultCode);
end;
It will be triggered only on a success installation.
Use ExecAsOriginalUser instead of Exec if you don't want the exe run as admin.

Inno Setup: Can the installer update itself?

My installer creates a folder with my app and the installer itself. The installer is later on used as an updater for the application.
All of this works well but I would like to update the installer itself and not just my application.
I download a zip from my server and expect everything inside the zip to override everything in the app folder (including the installer itself).
Every time I run the installer I get an error that a file is already in use.
Can the installer update itself?
You cannot replace running application.
You have these options:
Start the "updater" via batch file (referring to assumed shortcut to the updater in a Start menu or any other method of invocation), that makes a copy of the installer to a temporary location and runs the updater from there. When updating, update the original copy.
To avoid the batch file (and an unpleasant console window), you can use JScript. Or even make the installer (updater) do this itself (create a copy of itself, launch the copy, exit itself).
Use restartreplace flag in Files section entry to schedule installer/updater replace for the next Windows start.
Keeping the installer in the {app} directory is probably acceptable for small applications, for larger ones consider an updater, or even another location, (in the form of a feature request) {Backup} to refer to a path on some flash or removable drive.
Run the setup from the {app} directory and after the version check, download the installer to the {tmp} folder.
Exec the installer thus before quitting, keeping mind of possible mutex conditions in the code section of your script:
if Exec(ExpandConstant('{tmp}\{OutputBaseFilename}), '', '', SW_SHOW,
ewNoWait, ResultCode) then
// success/fail code follows
To copy the installer back to {app} the Install script will have this in Files:
[Files]
Source: "{srcexe}"; DestDir: "{app}"; Flags: external
Presumably the above line will not produce an error when the installer is actually run from {app}.
Then, to clean up, the next time the installer is run from the {src} (= {app}) directory, the downloaded one can be removed from the {tmp} directory with
DeleteFile({tmp}\{OutputBaseFilename})
I've run into this same problem recently. We have a main installer that manages a bunch of other setup packages for our applications, and I wanted to add some mechanism for this main installer to update itself.
I've managed to find a solution creating a second Inno Setup package that serves just as an updater for the main installer, and that updater goes embedded in the main installer.
So, we have a XML file in our website that gives the latest version available for the main installer:
[ InstallerLastVersion.xml ]
<?xml version="1.0" encoding="utf-8"?>
<installer name="Our Central Installer" file="OurInstaller.exe" version="1.0.0.1" date="10/15/2021" />
The main code for this auto-update functionality in the main installer is that:
[ OurInstaller.iss ]
[Files]
; This file won't be installed ('dontcopy' flag), it is just embedded
; into the installer to be extracted and executed in case it's necessary
; to update the Installer.
Source: ".\OurInstallerUpdater.exe"; Flags: dontcopy
[Code]
const
UrlRoot = 'http://ourwebsite.com/';
// Downloads a XML file from a website and loads it into XmlDoc parameter.
function LoadXml(XmlFile: String; var XmlDoc: Variant): Boolean;
begin
XmlDoc := CreateOleObject('MSXML2.DOMDocument');
XmlDoc.async := False;
Result := XmlDoc.Load(UrlRoot + XmlFile);
end;
// Checks if there's a newer version of the Installer
// and fires the updater if necessary.
function InstallerWillBeUpdated(): Boolean;
var
XmlDoc: Variant;
LastVersion, Filename, Param: String;
ResultCode: Integer;
begin
if not LoadXml('InstallerLastVersion.xml', XmlDoc) then
begin
Result := False;
Exit;
end;
// Gets the latest version number, retrieved from
// the XML file download from the website.
LastVersion := XmlDoc.documentElement.getAttribute('version');
// If this installer version is the same as the one available
// at the website, there's no need to update it.
if '{#SetupSetting("AppVersion")}' = LastVersion then
begin
Result := False;
Exit;
end;
if MsgBox('There is an update for this installer.' + #13#10 +
'Do you allow this installer to be updated right now?',
mbConfirmation, MB_YESNO) = IDNO then
begin
Result := False;
Exit;
end;
// Extracts the updater, that was embedded into this installer,
// to a temporary folder ({tmp}).
ExtractTemporaryFile('OurInstallerUpdater.exe');
// Gets the full path for the extracted updater in the temp folder.
Filename := ExpandConstant('{tmp}\OurInstallerUpdater.exe');
// The current folder where the installer is stored is going to be
// passed as a parameter to the updater, so it can save the new version
// of the installer in this same folder.
Param := ExpandConstant('/Path={src}');
// Executes the updater, with a command-line like this:
// OurInstallerUpdater.exe /Path=C:\InstallerPath
Result := Exec(Filename, Param, '', SW_SHOW, ewNoWait, ResultCode);
end;
function InitializeSetup(): Boolean;
begin
// Checks if the installer needs to be updated and fires the update.
// If the update is fired the installer must be ended, so it can be
// replaced with the new version. Returning this InitializeSetup()
// function with False already makes the installer to be closed.
if InstallerWillBeUpdated() then
begin
Result := False;
Exit;
end;
Result := True;
end;
Now to the updater code (I'm using the "new" DownloadTemporaryFile() function added in Inno Setup 6.1):
[ OurInstallerUpdater.iss ]
[Code]
const
UrlRoot = 'http://ourwebsite.com/';
Installer = 'OurInstaller.exe';
function InitializeSetup(): Boolean;
var
DestinationPath: String;
ResultCode: Integer;
begin
// Retrieves the parameter passed in the execution
// of this installer, for example:
// OurInstallerUpdater.exe /Path=C:\InstallerPath
// If no parameter was passed it uses 'C:\InstallerPath' as default.
// (where {sd} is the constant that represents the System Drive)
DestinationPath := ExpandConstant('{param:Path|{sd}\InstallerPath}') + '\' + Installer;
try
// Downloads the newer version of the installer to {tmp} folder.
DownloadTemporaryFile(UrlRoot + Installer, Installer, '', nil);
// Copies the downloaded file from the temp folder to the folder where
// the current installer is stored, the one that fired this updater.
FileCopy(ExpandConstant('{tmp}\') + Installer, DestinationPath, False);
// Runs the updated installer.
Exec(DestinationPath, '', '', SW_SHOW, ewNoWait, ResultCode);
except
MsgBox('The file ''' + Installer + ''' could not be downloaded.', mbInformation, MB_OK);
end;
// Returning False from this function implies that this
// updater can now be finished, since its goal has already
// been reached (to update the main installer).
Result := False;
end;
In this setting you have to build OurInstallerUpdater.exe before OurInstaller.exe, since the first one is embedded into the second one.
Some sources:
Inno Setup: Install file from Internet
Using {AppVersion} as a parameter for a function in Inno Setup
Exit from Inno Setup installation from [Code]
Is it possible to accept custom command line parameters with Inno Setup
How to get the installer path in Inno Setup?

sqlcmd.exe is hanging after running sql statement in inno package

I'm write installation package using inno for ms sql script. I have the following code:
strParam := '-U hel -P password -S ServerName -d test -Q "sp_test"';
try
Exec('sqlcmd.exe', strParam, '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
result := ResultCode = 0;
except
Exec('osql.exe', strParam, '', SW_SHOW, ewWaitUntilTerminated, ResultCode);
result := ResultCode = 0;
end;
Sp executes ok but black screen with sqlcmd.exe is hanging until either I type exit or close it. I want a window with sqlcmd.exe closed after sp is executed.
You seem to be trying to use sqlcmd first, and then using osql as a backup if that Exec throws. The documentation suggests to me that this won't work at all; you need if not Exec('sqlcmd', ...) then instead,
That aside, we use osql exclusively for our sql updates, and have never had issues with it not terminating. If you don't have a good reason for investing in two separate sql update programs, just use the one that works better. If that happens to be osql, so be it.
I ran into this today. My answer was that I have many differing versions of SQL command and the SQL program files. I took one path statement out for an older version and it started working

Possibility to synchronize a setup with Inno Setup and read out return code

is it possible to start a Inno Setup, that waits until the child process has finished? The current systems default behaviour is that the setup starts the "real" setup in temporary folder and goes further in command line. My aim is that the parent process should wait until the child finishes to read out the return code in errorlevel variable. I've made a picture for better understanding
My 2nd question is how Inno handles the setup exit codes. Where can they read out after setup has finished? If an error occurs in setup or user clicks cancel the env-variable %errorlevel% is always 0.
Thanks in advance
What you are trying to do is a function of the OS, not really InnoSetup. Use the following to do what you want from a command prompt or batch file:
start /wait setup.exe
echo %ERRORLEVEL%
The following code sample calls child.exe during the post-install step:
procedure CurStepChanged(CurStep: TSetupStep);
var
ErrorCode: integer;
begin
if (CurStep = ssPostInstall) then
begin
WizardForm.Hide;
ShellExec('open', 'child.exe', '', '', SW_SHOW, ewWaitUntilTerminated, ErrorCode);
WizardForm.Show;
if (ErrorCode <> 0) then
begin
// error handling
end;
end;
end;

Resources