Create desktop shortcup with inno Setup with custon target - installation

I would like to create a desktop shortcup with inno Setup.
I don't know what i must add into the configuration file of inno Setup to create my custom target.
Here is the line that i want to use :
"%userprofile%\AppData\Local\Google\Chrome SxS\Application\chrome.exe" --app=file://%userprofile%/Desktop/web/index.html --disable-web-security
And here is the content of the script configuration file of inno Setup :
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Icons]
Name: "{commondesktop}\SDK"; Filename: "{app}\index.html"; WorkingDir: "{app}"; IconFilename: {app}\tools\favicon.ico; Tasks: desktopicon

To specify icon parameters there's the Parameters parameter available for [Icons] section entries. The rest remains same as you already used. Just two notes; replace those environment variables by the corresponding path constants given by the Inno Setup scripting engine and be careful when using those variables when you're going to expand a file name with forward slashes (file://%userprofile%/..). Wouldn't such command line parameter fail in app. because it expands the path with baskslashes ?
In this script both mentioned issues should be considered:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName={pf}\My Program
[Icons]
Name: "{commondesktop}\SDK"; Filename: "{localappdata}\Google\Chrome SxS\Application\chrome.exe"; Parameters: "{code:GetParameters}"
[Code]
function ForwardSlashes(const Value: string): string;
begin
Result := Value;
StringChangeEx(Result, '\', '/', True);
end;
function GetParameters(Value: string): string;
var
S: string;
begin
S := ForwardSlashes(ExpandConstant('file://{userdesktop}/web/index.html'));
Result := Format('--app=%s --disable-web-security', [S]);
end;

Related

Inno Setup: turning exclusive Tasks into radio boxes

I'm working on an Inno Setup installer that has 4 radio boxes to let the user select which "flavor" they want to install. The documentation left me confused; should I use Tasks, Types, or Components for that?
It seems Tasks have radio-button behavior built-in: when the exclusive flag is set, only one of the tasks can be selected at a time. That's exactly what I want. So I have this code:
[Tasks]
Name: variant-a; Description: "A"; GroupDescription: "Variant"; Flags: exclusive
Name: variant-b; Description: "B"; GroupDescription: "Variant"; Flags: exclusive unchecked
Name: variant-c; Description: "C"; GroupDescription: "Variant"; Flags: exclusive unchecked
Name: variant-d; Description: "D"; GroupDescription: "Variant"; Flags: exclusive unchecked
How can I make the radio buttons show up? And how do I get the value of the Task that was chosen (e.g. "variant-a")?
The best is to use an existing script and see how it works
The documentation left me confused; should I use Tasks, Types, or
Components for that?
The added code parts have both : Task and Components
So decide what is more useful for your project.
In the examples directory are many useful examples that are well suited to respond to user input.
Copy the ..:...\Inno Setup 5\Examples\CodeExample1.iss to CodeExample1_ex.iss.
Open the copied file and insert the following code fragments.
Search for
OutputDir=userdocs:Inno Setup Examples Output
Insert below
//OutputDir=userdocs:Inno Setup Examples Output
[Tasks]
Name: variant_a; Description: "A"; GroupDescription: "Variant"; Components: main\a; Flags: exclusive
Name: variant_b; Description: "B"; GroupDescription: "Variant"; Components: main\b; Flags: exclusive unchecked
Name: variant_c; Description: "C"; GroupDescription: "Variant"; Components: main\c; Flags: exclusive unchecked
Name: variant_d; Description: "D"; GroupDescription: "Variant"; Components: main\d; Flags: exclusive unchecked
; Disabled we need it later -----------------------------------------------------
;Name: variant_a; Description: "A"; GroupDescription: "Variant"; Flags: exclusive
;Name: variant_b; Description: "B"; GroupDescription: "Variant"; Flags: exclusive unchecked
;Name: variant_c; Description: "C"; GroupDescription: "Variant"; Flags: exclusive unchecked
;Name: variant_d; Description: "D"; GroupDescription: "Variant"; Flags: exclusive
[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; Flags: fixed
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive
Name: "main"; Description: "variants"; Types: custom
Name: "main\a"; Description: "variant_a"; Types: custom; Flags: exclusive
Name: "main\b"; Description: "variant_b"; Types: custom; Flags: exclusive
Name: "main\c"; Description: "variant_c"; Types: custom full; Flags: exclusive
Name: "main\d"; Description: "variant_d"; Types: custom; Flags: exclusive
Search for the [Code] and add I : integer;
[Code]
var
MyProgChecked: Boolean;
MyProgCheckResult: Boolean;
FinishedInstall: Boolean;
I : integer;
Search for
procedure CurPageChanged(CurPageID: Integer);
Insert below
//procedure CurPageChanged(CurPageID: Integer);
var
Addtxt,WFCaption,WSelCaption : String;
Search for
Log('CurPageChanged(' + IntToStr(CurPageID) + ') called');
Insert below
//Log('CurPageChanged(' + IntToStr(CurPageID) + ') called');
if CurPageID = wpSelectComponents then begin
WFCaption := WizardForm.ComponentsList.ItemCaption[8];
Addtxt := ' <---------- If I where you I would take this';
if Pos(Addtxt,WFCaption) = 0 then WizardForm.ComponentsList.ItemCaption[8] := WFCaption + Addtxt;
end;
if CurPageID = wpSelectTasks then
begin
{ Only now is the TasksList populated }
if WizardForm.TasksList.Items.Count = 2 then begin
WSelCaption := Copy(WizardForm.TasksList.ItemCaption[1],1,2); //else
if Pos('C',WizardForm.TasksList.ItemCaption[1]) > 0 then
WSelCaption := WSelCaption + ' <-------- Your choice, my favorite, thank you :-)'#13#10+
' Not correct? Please go back and change the selection' else
WSelCaption := WSelCaption + ' <-------- Your choice : Not correct? Please go back and change the selection';
WizardForm.TasksList.ItemEnabled[0] := False;
WizardForm.TasksList.ItemCaption[1] := WSelCaption;
end else begin
For I := 1 to WizardForm.TasksList.Items.Count -1 do begin
if WizardForm.TasksList.Checked[I] then begin
WizardForm.TasksList.ItemCaption[I] := Copy(WizardForm.TasksList.ItemCaption[I],1,2) +
' <-------- Your choice : Not correct? Please change the selection';
end;
end; // for
end;
end;
Next are the constants used for the CurPageID
Example:
if CurPageID = wpSelectComponents then begin
wpWelcome, wpLicense, wpPassword, wpInfoBefore wpUserInfo,
wpSelectDir, wpSelectComponents wpSelectProgramGroup, wpSelectTasks,
wpReady wpPreparing, wpInstalling, wpInfoAfter, wpFinished
Change the individual code sections and look at the result.
It is easier and quicker to achieve results that are traceable.
Version A:
and the Task List result.
Why the trick with the .ComponentsList?
You do not need an extra event.
It is selected in the .ComponentsList and Controlled in the .Taskslist.
If you select nothing the .Taskslist is not visible.
All without extra code in the [Code] section.
Now we try Version B
Go to the [Task] section and look for
; Disabled we need it later -----------------------------------------------------
Disable the first four lines and enable the next four lines.
Search for procedure CurPageChanged(CurPageID: Integer);
Add above the Event WizardForm.TasksList.OnClickCheck := #TaskListClickCheck;
and the procedure for the .TasksList.
Here goes what you need to capture the selected value.
How or what you do with the Event WizardForm.TasksList.OnClickCheck and the freely selectable name of the function here : procedure TaskListClickCheck(Sender: TObject); depends on the requirements you want to achieve.
procedure TaskListClickCheck(Sender: TObject);
begin
For I := 1 to WizardForm.TasksList.Items.Count -1 do begin
if WizardForm.TasksList.Checked[I] then
WizardForm.TasksList.ItemCaption[I] := Copy(WizardForm.TasksList.ItemCaption[I],1,2) +
' <-------- Your choice : Not correct? Please change the selection' else
WizardForm.TasksList.ItemCaption[I] := Copy(WizardForm.TasksList.ItemCaption[I],1,2);
end;
end;
procedure InitializeWizard();
begin
WizardForm.TasksList.OnClickCheck := #TaskListClickCheck;
end;
//procedure CurPageChanged(CurPageID: Integer);
Now we need an event to intercept the selection.
Without extra code, the selection is always "A".
At last put before the final list, a little late right?
The user thought he was almost done!
The Name: "main"; Description: "variants"; Types: custom etc. part of the .ComponentsList is useless now. Best to disable it also.
Where can you find all this information?
Look at the Inno Setup help.
Search for WizardForm.TasksList
There we can see the property TasksList: **TNewCheckListBox**; read;
(Used Properties are blue)
So we click on TNewCheckListBox and get.
One or the other we can get a bit easier (direct way: value of a variable).
But here I did not want to make it too complicated and not use directly which only contributes to confusion.
Just using an existing code in an already existing script I do not understand as a code wrighting service.
To understand it only as an initial aid.

Prompt user in Inno Setup for file to be used in Shortcut

In Inno Setup I try to create this shortcut:
"C:\Program Files (x86)\MapInfo\Professional\MapInfow.exe" "{app}\DPImap.MBX"
It works fine with static text, however location of MapInfow.exe can vary so I like to ask the user for it.
This is what I did so far, however the shortcut is not created as intended
; Default value for silent installion
#define MapInfoDefault AddBackslash(GetEnv("ProgramFiles(x86)")) + "MapInfo\Professional\MapInfow.exe"
[Tasks]
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked
[Icons]
Name: {group}\DPImap; Filename: {code:MapInfoExecutable} {app}\DPImap.mbx
Name: {userdesktop}\DPImap; Filename: {code:MapInfoExecutable} {app}\DPImap.mbx; Tasks: desktopicon
[Code]
function MapInfoExecutable(Param: String): String;
var
FileName: string;
begin
FileName := '';
if GetOpenFileName('Locate your MapInfo Application', FileName, ExpandConstant('{pf32}'), 'Executable (*.exe)|*.exe', 'exe') then
Result := FileName
else
{ Return default #MapInfoDefault if user does not provide any file }
Result := ExpandConstant('{#MapInfoDefault}');
end;
How can I provide proper user dialog?
It should be:
[Icons]
Name: {group}\DPImap; Filename: "{code:MapInfoExecutable}"; \
Parameters: """{app}\DPImap.mbx"""
You should also cache the selected file name, otherwise you get the prompt at least twice, and probably even more times.
var
FileName: string;
function MapInfoExecutable(Param: String): String;
begin
if FileName = '' then
begin
if not GetOpenFileName(
'Locate your MapInfo Application', FileName, ExpandConstant('{pf32}'),
'Executable (*.exe)|*.exe', 'exe') then
begin
{ Return default #MapInfoDefault if user does not provide any file }
FileName := '{#MapInfoDefault}';
end;
end;
Result := FileName;
end;
Or actually even better, use a custom page, rather than a dialog, which pops up at uncontrollable moment.
See Inno Setup Prompt for external file location.
And even if you like the dialog, pop it on specific page/moment of your choice, cache the selected file name to a global variable and use the variable in the MapInfoExecutable.
Note that I've removed ExpandConstant from '{#MapInfoDefault}' - It's nonsense. See Evaluate preprocessor macro on run time in Inno Setup Pascal Script.

Inno Setup Jumps to Second Page if Program is Installed [duplicate]

This question already has answers here:
Inno Setup generated installer does not show "Select Destination Location" page on some systems
(3 answers)
Closed 4 years ago.
On first install everything runs smooth, but if I run the installer again it just jumps to the second page asking where i want to put the additional files, and then in the ready page only the parameters for the additional files folders is shown. The ignore version flag is set, what else could it be?
[Setup]
AppName={#MyAppName}
AppVersion={#MyAppVersion}
;AppVerName={#MyAppName} {#MyAppVersion}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
Compression=lzma
SolidCompression=yes
OutputBaseFilename=aeolian_meditation_setup
WizardSmallImageFile=compiler:greenlogo.bmp
WizardImageFile=compiler:glogo.bmp
DirExistsWarning=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
;Main program that will be installed in {app} folder
Source: "D:\ocean_swift\Flowstone Projects\Aeolian Meditation Advanced\OS Aeolian Meditation Advanced A191.exe"; DestDir: "{app}"; Flags: ignoreversion
;Database file that will installed where user choosed
Source: "D:\ocean_swift\Flowstone Projects\Aeolian Meditation Advanced\onts\OpenSans-Regular.ttf"; DestDir: "{fonts}"; Flags: onlyifdoesntexist; FontInstall: "Open Sans"
Source: "C:\Program Files (x86)\VSTPlugins\OS Aeolian Meditation Advanced A191.dll"; DestDir: "{code:GetDataDir}"
[Code]
var
DataDirPage: TInputDirWizardPage;
procedure InitializeWizard;
begin
// Create the page
DataDirPage := CreateInputDirPage(wpSelectDir,
'Select 32bit VST Plugin Directory', 'Where should the 32bit VSTi plugin be installed??',
'Select the folder in which Setup should install the 32bit VSTi plugin, then click Next.',
False, '');
DataDirPage.Add('');
DataDirPage.Values[0] := 'C:\Program Files (x86)\VSTPlugins\';
end;
procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
// Store the selected folder for further reinstall/upgrade
SetPreviousData(PreviousDataKey, 'DataDir', DataDirPage.Values[0]);
end;
function NextButtonClick(CurPageID: Integer): Boolean;
begin
// Set default folder if empty
if DataDirPage.Values[0] = '' then
DataDirPage.Values[0] := ExpandConstant('{sd}\DataDir');
Result := True;
end;
function UpdateReadyMemo(Space, NewLine, MemoUserInfoInfo, MemoDirInfo, MemoTypeInfo,
MemoComponentsInfo, MemoGroupInfo, MemoTasksInfo: String): String;
var
S: String;
begin
// Fill the 'Ready Memo' with the normal settings and the custom settings
S := '';
S := S + MemoDirInfo + NewLine + NewLine;
S := S + '32bit VSTi' + NewLine;
S := S + Space + DataDirPage.Values[0] + NewLine;
Result := S;
end;
function GetDataDir(Param: String): String;
begin
{ Return the selected DataDir }
Result := DataDirPage.Values[0];
end;
If you look here you will see that the default value for DisableProgramGroupPage is auto. As described there:
If this is set to auto, at startup Setup will look in the registry to
see if the same application is already installed, and if so, it will
not show the Select Start Menu Folder wizard page.
If you review the other Disable entries in the help file you will see them behave the same. It is logical to only show these pages during a new install. Change the default behaviour by setting these to no.

using Desktop App Converter sticks at "Waiting for installer process to complete inside Isolated Environment"

I am trying to convert an Install .exe file I made with inno-setup to an appx file using the Desktop App Converter from Microsoft. It hangs every time at "Waiting for installer to process to complete inside Isolated Environment".
The command that I am using in Desktop App Converter is:
DesktopAppConverter.exe -Installer "C:\Users\Desktop\Output\setup.exe" -Destination "C:\Users\Desktop\MyProgram\" -PackageName "MyProgramApps" -Publisher "Me"
-Version 0.1.4.0 -MakeAppx -Verbose -InstallerArguments "/VERYSILENT" -PackagePublisherDisplayName "MyApps" -PackageDisplayName "MyProgram" -AppDisplayName "MyProgram" -AppId "MyProgram"
When I run "MyProgram.exe from the command line using "/VERYSILENT" it installs completely silently.
The script from Inno-Setup is:
#define MyAppName "MyProgram"
#define MyAppVersion "0.1.7"
#define MyAppPublisher "MyApps"
#define MyAppExeName "MyProgram.exe"
[Setup]
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppPublisher={#MyAppPublisher}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=C:\Users\Desktop\Output
OutputBaseFilename=thirteenth_setup
Compression=lzma
SolidCompression=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "C:\Users\Desktop\resources\MyProgram.exe"; DestDir: "{app}"; Flags: ignoreversion
#define JavaInstaller "jre-8u151-windows-x64.exe"
Source: "{#JavaInstaller}"; DestDir: "{tmp}"; Flags: dontcopy
[Icons]
Name: "{commonprograms}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; \
Description: "{cm:LaunchProgram,{#StringChange(MyAppName,'&', '&&' )}}"; \
Flags: nowait postinstall skipifsilent
[Code]
const
REQUIRED_JAVA_VERSION = '1.7';
function isJavaInstalled(): Boolean;
var
JavaVer : String;
tmpFileName,
pathJavaExe: String;
isGoodJavaVersion,
isFoundJavaPath: Boolean;
ResultCode: Integer;
ExecStdout: AnsiString;
begin
{ *** check in registry }
{ sets variables: }
{ JavaVer }
{ isGoodJavaVersion }
if RegQueryStringValue(HKLM, 'SOFTWARE\JavaSoft\Java Runtime Environment',
'CurrentVersion', JavaVer) AND (JavaVer <> '') OR
RegQueryStringValue(HKLM64, 'SOFTWARE\JavaSoft\Java Runtime Environment',
'CurrentVersion', JavaVer) AND (JavaVer <> '') then begin
Log('* Java Entry in Registry present. Version: ' + JavaVer);
isGoodJavaVersion := CompareStr(JavaVer, REQUIRED_JAVA_VERSION) >= 0;
end;
{ add additional checks, for example by searching the PATH, }
{ or by running `java -version` }
Result := isGoodJavaVersion;
end;
procedure ExtractInstaller;
begin
ExtractTemporaryFile('{#JavaInstaller}');
end;
[Run]
Filename: "{tmp}\{#JavaInstaller}"; Parameters: "SPONSORS=0"; \
StatusMsg: "Java Runtime Enviroment not installed on your system. Installing..."; \
Check: not isJavaInstalled; BeforeInstall: ExtractInstaller;
I think it has something to do with:
[Run]
Filename: "{tmp}\{#JavaInstaller}"; Parameters: "SPONSORS=0"; \
StatusMsg: "Java Runtime Enviroment not installed on your system. Installing..."; \
Check: not isJavaInstalled; BeforeInstall: ExtractInstaller;
because when I run it without that 'run' statement then DAC runs to a finish. But of course then the Java installer does not run.
You can also convert the packages with the new free Express edition from Advanced Installer, developed in partnership with Microsoft, its purpose is to complement the Desktop App Converter.
For example, the installation of your INNO package can be interactive, with UI, so you can manually run the installer and complete the installation, thus should be able to avoid the above problem.
It has a GUI that allows for advanced customization of the APPX packages, without requiring you to have knowledge about the internals package schemas.
If you have any questions about it, let me know, would love to help.
Disclaimer: I work on the team that builds Advanced Installer.

How to separate a Inno Setup script into multiple files?

I have two setup scripts that share common code. It is possible to refactor them?
One way of doing that is having a file for common code which will be referenced by each script.
Is this possible?
Depending on the version of InnoSetup you are using, you can use an include file. The example below uses three files (main.iss, code.iss, commonfiles.iss):
Main File:
; Script generated by the Inno Setup Script Wizard.
; SEE THE DOCUMENTATION FOR DETAILS ON CREATING INNO SETUP SCRIPT FILES!
#define MyAppName "My Program"
#define MyAppVerName "My Program 1.5"
#define MyAppPublisher "My Company, Inc."
#define MyAppURL "http://www.example.com/"
#define MyAppExeName "MyProg.exe"
[Setup]
AppName={#MyAppName}
AppVerName={#MyAppVerName}
AppPublisher={#MyAppPublisher}
AppPublisherURL={#MyAppURL}
AppSupportURL={#MyAppURL}
AppUpdatesURL={#MyAppURL}
DefaultDirName={pf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: unchecked
[Files]
Source: "C:\util\innosetup\Examples\MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion
#include "CommonFiles.iss"
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"
Name: "{commondesktop}\{#MyAppName}"; Filename: "{app}\{#MyAppExeName}"; Tasks: desktopicon
[Run]
Filename: "{app}\{#MyAppExeName}"; Description: "{cm:LaunchProgram,{#MyAppName}}"; Flags: nowait postinstall skipifsilent
#include "code.iss"
CommonFiles.iss:
Source: "Common.DLL"; DestDir: "{app}"; Flags: ignoreversion
Code.iss:
[code]
function IsDotNET11Detected(): boolean;
// Indicates whether .NET Framework 1.1 is installed.
var
success: boolean;
install: cardinal;
begin
success := RegQueryDWordValue(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322', 'Install', install);
Result := success and (install = 1);
end;
function InitializeSetup(): Boolean;
begin
if not IsDotNET11Detected then begin
MsgBox('This software requires the Microsoft .NET Framework 1.1.'#13#13
'Please use Windows Update to install this version,'#13
'and then re-run the setup program.', mbInformation, MB_OK);
Result := false;
end else
begin
MsgBox('Framework installed',mbInformation, MB_OK);
Result := true;
end
end;

Resources