Inno Setup - Register components as an administrator - excel

Based on the excellent Excel add-in installer (Daniel's XL Toolbox), I have built a setup file that among other things needs to register some ActiveX's
[Files]
; The include file makes adds all .XLA and .XLAM files contained in the
; SOURCEDIR to the project.
Source: "c:\source\path\MSCOMCTL.OCX"; \
DestDir: "\users\public\EzPasteFiles"; Flags: regserver
Source: "c:\source\path\DAS_AX_Knob.dll"; \
DestDir: "\users\public\EzPasteFiles"; Flags: regserver
Source: "c:\source\path\GIF89.DLL"; \
DestDir: "\users\public\EzPasteFiles"; Flags: regserver
I need the addin to install, then before starting to register the files a check is done about administrator rights and if the user has none, a message is displayed asking for entering the admin password so that registration can take place. I am aware that it can be done at the beginning of the setup, but then the addin will not be activated, if it is a standard user account. The addin needs registered components, a standard user can't install it properly.
I am looking for something like this to fire before the registration starts:
MyProgChecked := not(IsAdminLoggedOn or IsPowerUserLoggedOn);
if MyProgChecked = True then
begin
MsgBox(
'Kindly notice:' #13#13
'It seems as you are not looged as an administrator' #13#13
'Please abort and reinstall EzPaste AS an administrator' #13#13
'(To install As an Adminstrator, just save the exe setup anywhere then Right Click on it to get to this feature or ask your IT administrator for proper directives)',
mbConfirmation, MB_OK);
{ Popup message asking for Pwd }
ExitProcess(0);
end;
I am naturally open for any other approach
I'll be glad also to understand how a domain user (Windows server) without admin rights should proceed to install the addin.

You can execute regsvr32.exe "as administrator", this way:
[Files]
Source: "MyDll.dll"; DestDir: "{app}"; AfterInstall: RegMyDll
[Code]
procedure RegMyDll;
var
Path: string;
RegSvr: string;
Params: string;
Registered: Boolean;
ErrorCode: Integer;
begin
Path := ExpandConstant(CurrentFilename);
RegSvr := 'regsvr32.exe';
Params := Format('/s "%s"', [Path]);
Log(Format('Registering %s using "%s" %s', [Path, RegSvr, Params]));
Registered :=
ShellExec('runas', RegSvr, Params, '', SW_HIDE, ewWaitUntilTerminated, ErrorCode);
if Registered and (ErrorCode = 0) then
begin
Log(Format('Registered %s', [Path]));
end
else
begin
MsgBox(Format('Registering %s failed with code %d', [Path, ErrorCode]), mbError, MB_OK);
end;
end;
Alternative implementation is to create subinstaller for the registration only that will require Administrator privileges.
For a similar example, see Inno Setup - Access unprivileged account folders from installer that requires privileges.
Or use an opposite approach. Require administrator privileges using
[Setup]
PrivilegesRequired=admin
(which is default)
But deploy files to the original user folder.
See my answer to Inno Setup always installs into admin's AppData directory.

Related

Perform DeleteFile only on NEW installation [duplicate]

My InnoSetup script opens a web page (with the user's default browser) at the end of the install process:
[Run]
Filename: http://example.com; Flags: shellexec
However, I'd like the web page to not be opened if the app already exists, i.e., if the user is installing a new version of the program. The web page should only be opened after the initial install. (I assume it's worth mentioning that the install includes an AppID, obviously, and enters values in the registry beside installing files.)
Thank you, as always -- Al C.
Yes, this is easy to do with scripting.
Just write
[Run]
Filename: "http://example.com"; Flags: shellexec; Check: NotAnUpdate
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpInstalling then
IsUpdate := FileExists(ExpandConstant('{app}\TheFileNameOfMyApp.exe'));
end;
function NotAnUpdate: Boolean;
begin
result := not IsUpdate;
end;
The answer by #AndreasRejbrand won't work, if user chooses to install the executable to a different location than the last time.
You can query installer-specific Inno Setup registry keys:
#define AppId "your-app-id"
#define SetupReg \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
#define SetupAppPathReg "Inno Setup: App Path"
[Setup]
AppId={#AppId}
...
[Run]
Filename: "https://www.example.com/"; Flags: shellexec; Check: not IsUpgrade
...
[Code]
function IsUpgrade: Boolean;
var
S: string;
begin
Result :=
RegQueryStringValue(HKLM, '{#SetupReg}', '{#SetupAppPathReg}', S) or
RegQueryStringValue(HKCU, '{#SetupReg}', '{#SetupAppPathReg}', S);
end;
For an example how to use IsUpgrade in [Code] section, see
Excludes part of Code section in ssPostInstall step if installation is update in Inno Setup
Check this if your "AppId" contains a left-curly-bracket:
Checking if installation is fresh or upgrade does not work when AppId contains a curly bracket

How to use Inno Setup to run a command like steam://

I am trying to make my Inno Setup program to run this command steam://
This command is used to open Steam program via the windows RUN tool.
I press WindowsKey+R and type the command steam:// and it opens the Steam program.
How can i make Inno Setup call this command?
I tried the following without success:
[Run]
Filename: "C:\Users\LUCAS\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Accessories\Run.lnk"; Parameters: "steam://;
also tried that code bellow, and calling AfterInstall: RunOtherInstaller; on [Files] section, but it gives error on installation: %1 is not a valid Win32 application
[Code]
procedure RunOtherInstaller;
var
ResultCode: Integer;
begin
if not Exec(ExpandConstant('C:\Users\LUCAS\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\Accessories\Run.lnk'), 'steam://', '', SW_SHOWNORMAL,
ewWaitUntilTerminated, ResultCode)
then
MsgBox('Error!!' + #13#10 +
SysErrorMessage(ResultCode), mbError, MB_OK);
end;
This link is a little strange... It actually points to nowhere when i try to follow it, but it is what calls the windows RUN tool.
I know i could call the Steam.exe from the default folder C:\Program Files (x86)\Steam\Steam.exe but i am trying to avoid problems with users who not have Steam on default folder... So i am trying to use this method running this "External Protocol" (i dont know if this is the right name for it): steam://
You can check registry for Steam location.
Part of my script for triggering installation:
[Code]
function SteamNotInstalled(): Boolean;
var
Path: String;
ErrorCode: Integer;
begin
Result := True;
if (RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\Valve\Steam',
'InstallPath', Path)) and (FileExists(Path + '\Steam.exe')) then begin
ShellExec('', ExpandConstant('"' + Path + '\Steam.exe' + '"'), ' -install' + ExpandConstant(' "{src}"'),
'', SW_SHOW, ewNoWait, ErrorCode);
Result := False;
end;
end;
Or you can use shellexec in [Run] section
You can open the steam:// URL as any other URL.
procedure OpenUrl(Url: string);
var
ErrorCode: Integer;
begin
ShellExec('open', Url, '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;
Or use postinstall [Run] section entry:
[Run]
Filename: steam://xxx; Description: "Run game"; Flags: postinstall shellexec
See also
How to open a web site after uninstallation?
Inno Setup Compiler: How to auto start the default browser with given url?

PowerShell Script after install

Newbie question: I would like to run a powershell script (.ps1) at the end of the inno-setup install. Can anyone give me a tip on where to put this? I want the user prompted to be asked if he wants to run this script.
Oh yes, what this script does is run netsh.exe to open up a port, the script is clever and it grabs Env:username and Env:userdomain from the current context. Would the context be the admin who is running the setup? or would it be the original user that ran the setup.exe?
Another way is to run the script using the ShellExec from the code.
[Files]
Source: "yourPowershell.ps1"; DestDir: "{app}"; Flags: overwritereadonly replacesameversion promptifolder;
[Tasks]
Name: "runpowershell"; Description: "Do you want to run Powershell script?"
[Code]
procedure CurStepChanged(CurStep: TSetupStep);
var
ErrorCode: Integer;
ReturnCode: Boolean;
begin
if CurStep = ssPostInstall then begin
if(IsTaskSelected('runpowershell')) then begin
ExtractTemporaryFile('yourPowershell.ps1');
ReturnCode := ShellExec('open', '"PowerShell"', ExpandConstant(' -ExecutionPolicy Bypass -NoLogo -NonInteractive -NoProfile -WindowStyle Hidden -File "{tmp}\YourPowershell.ps1"'), '', SW_SHOWNORMAL, ewWaitUntilTerminated, ErrorCode);
if (ReturnCode = False) then
MsgBox('Message about problem. Error code: ' + IntToStr(ErrorCode) + ' ' + SysErrorMessage(ErrorCode), mbInformation, MB_OK);
end;
end;
[Run]
.....; Description: Run Script; Flags: postinstall
(See the help for more details.) By default this will display a checkbox and run under the original user's context (although it depends a bit on how the installer is run).
You might want to reconsider this approach, though; if you are performing a machine-wide install then you should probably open the port machine-wide too. You can do this with pure Inno code calling WinAPIs -- no powershell required. (Which is a good thing, because it might not be installed.)
Alternatively if you want to keep it a per-user setting you should consider making your application prompt the user for a decision on first run. After all, why give an option to only one of the many possible users of your app?

How to get Inno Setup to unzip a file it installed (all as part of the one installation process)

To save bandwidth/space as well as prevent accidental meddling, the installation files for a database product (call it Ajax), have been zipped up (call that file "AJAX_Install_Files.ZIP). I would like to have Inno-Setup "install" (i.e., copy) the AJAX_Install_Files.ZIP file to the destination, and then Unzip the files into the same folder where the .ZIP file is located. A subsequent program would be fired off by Inno Setup to actually run the install of product "Ajax".
I've looked through the documentation, FAQ, and KB at the Inno Setup website, and this does not seem possible other than writing a Pascal script (code) - would that be correct, or are there are any alternative solutions?
You can use an external command line tool for unzipping your archive, see here for example. Put it in your [Files] section:
[Files]
Source: "UNZIP.EXE"; DestDir: "{tmp}"; Flags: deleteafterinstall
Then call it in your [Run] section, like this:
[Run]
Filename: "{tmp}\UNZIP.EXE"; Parameters: "{tmp}\ZipFile.ZIP -d C:\TargetDir"
(You'll probably want to take your target directory from a script variable, so there is some more work that needs to be done)
You can use the shell Folder.CopyHere method to extract a ZIP.
const
SHCONTCH_NOPROGRESSBOX = 4;
SHCONTCH_RESPONDYESTOALL = 16;
procedure UnZip(ZipPath, TargetPath: string);
var
Shell: Variant;
ZipFile: Variant;
TargetFolder: Variant;
begin
Shell := CreateOleObject('Shell.Application');
ZipFile := Shell.NameSpace(ZipPath);
if VarIsClear(ZipFile) then
RaiseException(
Format('ZIP file "%s" does not exist or cannot be opened', [ZipPath]));
TargetFolder := Shell.NameSpace(TargetPath);
if VarIsClear(TargetFolder) then
RaiseException(Format('Target path "%s" does not exist', [TargetPath]));
TargetFolder.CopyHere(
ZipFile.Items, SHCONTCH_NOPROGRESSBOX or SHCONTCH_RESPONDYESTOALL);
end;
Note that the flags SHCONTCH_NOPROGRESSBOX and SHCONTCH_RESPONDYESTOALL work on Windows Vista and newer.
For an example of extracting some files only, see:
How to get Inno Setup to unzip a single file?
I answered a very similar question and some of the details apply.
I would question why you need a ZIP file of the contents? I personally would place the uncompressed files into the setup. I would then have two [category] entries one for the application and one for the data. Default both the be checked.
This would allow the users to install a fresh set of the data if needed at a later date.
If you really want a ZIP file and want to keep it easy you could, ship both the zip files and the uncompressed files in the same setup.
Update:
By default files that get placed in your setup.exe are compressed.
You can also have the files extracted to a temporary location so you can run your
installation application, then have them deleted.
[Files]
Source: "Install1.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
Source: "Install2.SQL"; DestDir: "{tmp}"; Flags:deleteafterinstall;
You can just create silent self-extracting archive (SFX) archive, example described here how to create SFX archive for stuff you need, and write Pascal code to just run it like this (script for Inno Setup 6.0.2):
[Tasks]
Name: "intallSenselockDriver"; Description: "Install Senselock driver."; GroupDescription: "Install the necessary software:";
[Code]
function ExecTmpFile(FileName: String): Boolean;
var
ResultCode: Integer;
begin
if not Exec(ExpandConstant('{tmp}\' + FileName), '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode)
then
begin
MsgBox('Other installer failed to run!' + #13#10 + SysErrorMessage(ResultCode), mbError, MB_OK);
Result := False;
end
else
Result := True;
end;
procedure RunOtherInstallerSFX(ArchiveName: String; ExePath: String);
begin
ExtractTemporaryFile(ArchiveName);
ExecTmpFile(ArchiveName);
ExecTmpFile(ExePath);
end;
function PrepareToInstall(var NeedsRestart: Boolean): String;
begin
if WizardIsTaskSelected('intallSenselockDriver') then
RunOtherInstallerSFX('1_senselock_windows_3.1.0.0.exe', '1_senselock_windows_3.1.0.0\InstWiz3.exe');
Result := '';
end;
It worked perfectly for me.
Using Double quotes worked for me.
Single quotes were not working.
[Files]
Source: "unzip.exe"; DestDir: "{userappdata}\{#MyAppName}\{#InputFolderName}"; Flags: ignoreversion
[Run]
Filename: "{userappdata}\{#MyAppName}\{#InputFolderName}\unzip.exe"; Parameters: " ""{userappdata}\{#MyAppName}\{#InputFolderName}\ZIPFILENAME.zip"" -d ""{userappdata}\{#MyAppName}\{#InputFolderName}"" "; Flags: runascurrentuser

Can Inno Setup respond differently to a new install and an update?

My InnoSetup script opens a web page (with the user's default browser) at the end of the install process:
[Run]
Filename: http://example.com; Flags: shellexec
However, I'd like the web page to not be opened if the app already exists, i.e., if the user is installing a new version of the program. The web page should only be opened after the initial install. (I assume it's worth mentioning that the install includes an AppID, obviously, and enters values in the registry beside installing files.)
Thank you, as always -- Al C.
Yes, this is easy to do with scripting.
Just write
[Run]
Filename: "http://example.com"; Flags: shellexec; Check: NotAnUpdate
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpInstalling then
IsUpdate := FileExists(ExpandConstant('{app}\TheFileNameOfMyApp.exe'));
end;
function NotAnUpdate: Boolean;
begin
result := not IsUpdate;
end;
The answer by #AndreasRejbrand won't work, if user chooses to install the executable to a different location than the last time.
You can query installer-specific Inno Setup registry keys:
#define AppId "your-app-id"
#define SetupReg \
"Software\Microsoft\Windows\CurrentVersion\Uninstall\" + AppId + "_is1"
#define SetupAppPathReg "Inno Setup: App Path"
[Setup]
AppId={#AppId}
...
[Run]
Filename: "https://www.example.com/"; Flags: shellexec; Check: not IsUpgrade
...
[Code]
function IsUpgrade: Boolean;
var
S: string;
begin
Result :=
RegQueryStringValue(HKLM, '{#SetupReg}', '{#SetupAppPathReg}', S) or
RegQueryStringValue(HKCU, '{#SetupReg}', '{#SetupAppPathReg}', S);
end;
For an example how to use IsUpgrade in [Code] section, see
Excludes part of Code section in ssPostInstall step if installation is update in Inno Setup
Check this if your "AppId" contains a left-curly-bracket:
Checking if installation is fresh or upgrade does not work when AppId contains a curly bracket

Resources