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.
Related
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.
I would like to disable and set to gray color, or set to readonly, some task checkboxes, the checkboxes that are checked in this image:
I'm not looking for other kind of approach, I want to make visible those Tasks but make their checkboxes uncheckeable, that's all, this way the user can see what is going to be installed and what is restricted by default.
My Install script looks like this:
[Tasks]
; VS Optional Features
Name: blend; Description: Blend; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: foundationclass; Description: Microsoft Foundation Classes for C++; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: lightswitch; Description: Microsoft LightSwitch; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: officedevelopertools; Description: Microsoft Office Developer Tools; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: sqldatatools; Description: Microsoft SQL Server Data Tools; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: webdevelopertools; Description: Microsoft Web Developer Tools; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: silverlightsdk; Description: SilverLight Developer Kit; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: Win8SDK; Description: Tools For Maintaining Store Apps For Windows 8; GroupDescription: VS Optional Features:; Flags: Unchecked
Name: WindowsPhone80; Description: Windows Phone 8.0 SDK; GroupDescription: VS Optional Features:; Flags: Unchecked
; VS Hidden Features
Name: netfx4; Description: .NET FX 4; GroupDescription: VS Hidden Features:
Name: netfx45; Description: .NET FX 4.5; GroupDescription: VS Hidden Features:
Name: bliss; Description: Bliss; GroupDescription: VS Hidden Features:
Name: helpviewer; Description: Microsoft Help Viewer 2.1; GroupDescription: VS Hidden Features:
Name: portablelibrary; Description: Microsoft Portable Library Multi-Targeting Pack; GroupDescription: VS Hidden Features:
Name: report; Description: Microsoft Report Viewer Add-On for Visual Studio 2013; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: silverlight; Description: Microsoft Silverlight 5 SDK; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqldac; Description: Microsoft SQL DAC; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqldom; Description: Microsoft SQL DOM; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqllocaldb; Description: Microsoft SQL Server 2013 Express LocalDB; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqlmanagementobjects; Description: Microsoft SQL Server 2013 Management Objects; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqlclr; Description: Microsoft SQL Server 2013 System CLR Types; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqltran; Description: Microsoft SQL Server 2013 Transact-SQL; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sqlce; Description: Microsoft SQL Server Compact Edition; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: c_compilers; Description: Microsoft Visual C++ 2013 Compilers; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: c_core; Description: Microsoft Visual C++ 2013 Core Libraries; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: c_debug; Description: Microsoft Visual C++ 2013 Debug Runtime; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: c_designtime; Description: Microsoft Visual C++ 2013 Designtime; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: c_extendedlibraries; Description: Microsoft Visual C++ 2013 Extended Libraries; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: intellitrace; Description: Microsoft Visual Studio 2013 IntelliTrace; GroupDescription: VS Hidden Features:
Name: storyboarding; Description: Microsoft Visual Studio Team Foundation Server 2013 Storyboarding; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: sdk3; Description: SDK Tools 3; GroupDescription: VS Hidden Features:
Name: sdk4; Description: SDK Tools 4; GroupDescription: VS Hidden Features:
Name: analytics; Description: Visual Studio Analytics; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: dotfuscator; Description: Visual Studio Dotfuscator; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: javascript; Description: Visual Studio Extensions for Windows Library for JavaScript; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: profiler; Description: Visual Studio Profiler; GroupDescription: VS Hidden Features:; Flags: Unchecked
Name: winsdk; Description: Windows Software Development Kit; GroupDescription: VS Hidden Features:; Flags: Unchecked
Is this possibly to accomplish?
I didn't found any Task flag that helps me to do this, in the other hand, I've seen other questions in StackOverflow but are related to readonly checkboxes and it uses pascal-script code, I'm not a pascal script code and I'm not sure whether that is what I need to do because I'm not creating and instancing manually the checkboxes in the Form, I mean that I don't have any control on those checkboxes+labels, I'm just adding tasks in the Task section.
UPDATE
I'm using the pascal-script code below to disable the desired items, but when I run my installer I get this error, it says that the index is out of bounds, why?, I'm using the proper chekbox indexes and I've verified the indexes seeying the resulting task page... I think that the problem is the wpSelectTasks, it is an integrated constant?, anyways I've tried to specify a constant with the pagenumber of the tasks page and I still get the same error, and the error occurs when I change the selected page using the 'Next' button (not 'Back'):
// Disable Tasks
procedure CurPageChanged(CurPageID: Integer);
begin
// if we have entered the tasks selection page, disable the specified Tasks.
if CurPageID = wpSelectTasks then
WizardForm.TasksList.ItemEnabled[11] := False;
WizardForm.TasksList.ItemEnabled[12] := False;
WizardForm.TasksList.ItemEnabled[13] := False;
WizardForm.TasksList.ItemEnabled[14] := False;
WizardForm.TasksList.ItemEnabled[15] := False;
WizardForm.TasksList.ItemEnabled[30] := False;
WizardForm.TasksList.ItemEnabled[32] := False;
WizardForm.TasksList.ItemEnabled[33] := False;
end;
// Disable Tasks - END
I have more code for UI customizations and I don't know if some thing is in conflict with the other procedure, the entire [Code] section is this:
[Code]
// Disable Tasks
procedure CurPageChanged(CurPageID: Integer);
begin
// if we have entered the tasks selection page, disable the specified Tasks.
if CurPageID = wpSelectTasks then
WizardForm.TasksList.ItemEnabled[11] := False;
WizardForm.TasksList.ItemEnabled[12] := False;
WizardForm.TasksList.ItemEnabled[13] := False;
WizardForm.TasksList.ItemEnabled[14] := False;
WizardForm.TasksList.ItemEnabled[15] := False;
WizardForm.TasksList.ItemEnabled[30] := False;
WizardForm.TasksList.ItemEnabled[32] := False;
WizardForm.TasksList.ItemEnabled[33] := False;
end;
// Disable Tasks - END
// Installer UI Customizations
const
Custom_Height = 570;
Page_Color = $7b2b68;
Page_Color_Alternative1 = clblack;
Page_Color_Alternative2 = clwhite;
Font_Color = $fffbff;
var
DefaultTop,
DefaultLeft,
DefaultHeight,
DefaultBackTop,
DefaultNextTop,
DefaultCancelTop,
DefaultBevelTop,
DefaultOuterHeight: Integer;
procedure InitializeWizard();
begin
DefaultTop := WizardForm.Top;
DefaultLeft := WizardForm.Left;
DefaultHeight := WizardForm.Height;
DefaultBackTop := WizardForm.BackButton.Top;
DefaultNextTop := WizardForm.NextButton.Top;
DefaultCancelTop := WizardForm.CancelButton.Top;
DefaultBevelTop := WizardForm.Bevel.Top;
DefaultOuterHeight := WizardForm.OuterNotebook.Height;
// Page sizes
WizardForm.Height := Custom_Height;
WizardForm.InnerPage.Height := WizardForm.InnerPage.Height + (Custom_Height - DefaultHeight);
WizardForm.LicensePage.Height := WizardForm.LicensePage.Height + (Custom_Height - DefaultHeight);
// Control locations
WizardForm.BackButton.Top := DefaultBackTop + (Custom_Height - DefaultHeight);
WizardForm.Bevel.Top := DefaultBevelTop + (Custom_Height - DefaultHeight);
WizardForm.CancelButton.Top := DefaultCancelTop + (Custom_Height - DefaultHeight);
WizardForm.LicenseAcceptedRadio.Top := WizardForm.LicenseAcceptedRadio.Top + (Custom_Height - DefaultHeight);
WizardForm.LicenseNotAcceptedRadio.Top := WizardForm.LicenseNotAcceptedRadio.Top + (Custom_Height - DefaultHeight);
WizardForm.NextButton.Top := DefaultNextTop + (Custom_Height - DefaultHeight);
WizardForm.Top := DefaultTop - (Custom_Height - DefaultHeight) div 2;
// Control Sizes
WizardForm.InfoBeforeMemo.Height := (Custom_Height - (DefaultHeight / 2));
WizardForm.InnerNotebook.Height := WizardForm.InnerNotebook.Height + (Custom_Height - DefaultHeight);
WizardForm.LicenseMemo.Height := WizardForm.LicenseMemo.Height + (Custom_Height - DefaultHeight);
WizardForm.OuterNotebook.Height := WizardForm.OuterNotebook.Height + (Custom_Height - DefaultHeight);
WizardForm.Taskslist.Height := (Custom_Height - (DefaultHeight / 2));
WizardForm.WizardBitmapImage.Height := (Custom_Height - (DefaultHeight / 5));
// Page colos
WizardForm.color := Page_Color_Alternative1;
WizardForm.FinishedPage.Color := Page_Color;
WizardForm.InfoBeforeMemo.Color := clGray;
WizardForm.InnerPage.Color := Page_Color;
WizardForm.LicensePage.Color := Page_Color;
WizardForm.MainPanel.Color := Page_Color;
WizardForm.SelectComponentsPage.Color := Page_Color;
WizardForm.SelectDirPage.Color := Page_Color;
WizardForm.Taskslist.Color := Page_Color;
WizardForm.WelcomePage.color := Page_Color;
// Font colors
WizardForm.Font.color := Font_Color;
//WizardForm.InfoBeforeMemo.font.Color := Font_Color;
WizardForm.Licensememo.font.Color := Font_Color;
WizardForm.MainPanel.font.Color := Font_Color;
WizardForm.PageDescriptionLabel.font.color := Font_Color;
WizardForm.PageNameLabel.font.color := Font_Color;
WizardForm.Taskslist.font.Color := Font_Color;
WizardForm.WelcomeLabel1.font.color := Font_Color;
WizardForm.WelcomeLabel2.font.color := Font_Color;
end;
// Installer UI Customizations - END
The current solution for this, is specified by a #Tlama's answer in this question.
Very new to InnoSetup, but I could not find any documentation on this. I would like to implement a condition where if the user has already installed a specific component, it will not allow them to install another specific component.
For example: If Bob has previously installed ComponentA, and ties to install ComponentB, it will error our with a warning "Cannot install ComponentB while ComponentA currently installed"
This is what I have come up with so far:
procedure CurPageChanged(CurPageID: Integer);
var
Value: string;
UninstallKey: string;
begin
UninstallKey := 'Software\Microsoft\Windows\CurrentVersion\Uninstall\' +
ExpandConstant('{#SetupSetting("AppId")}') + '_is1';
Result := (RegQueryStringValue(HKLM, UninstallKey, 'Inno Setup: Selected Components', Value) or
RegQueryStringValue(HKCU, UninstallKey, 'Inno Setup: Selected Components', Value)) and (Value <> '');
if CurPageID = wpSelectComponents then
if Result = WizardForm.ComponentsList.ItemCaption[1] then
begin
WizardForm.ComponentsList.Checked[1] := False;
WizardForm.ComponentsList.ItemEnabled[1] := True;
WizardForm.ComponentsList.Checked[2] := False;
WizardForm.ComponentsList.ItemEnabled[2] := False;
WizardForm.ComponentsList.Checked[3] := False;
WizardForm.ComponentsList.Enabled[3] := True;
end;
end;
end;
I know I do not quite have the Registry Query exactly right for selected components.. I feel like I'm close though. The problem is, Result may have multiple components in it. like (apple,orange,mango) but I want the statement to still be true if just "mango" exists.
Think you could do this in another way:
Use Flags:
exclusive
example:
[Types]
Name: "full"; Description: "Full"; Flags: iscustom
[Components]
Name: "connect"; Description: "Mainsection"; Types: "full" ;Flags: fixed
Name: "connect\compA"; Description: "ComponentA"; Types: "full"; Flags: exclusive
Name: "connect\compB"; Description: "ComponentB"; Flags: exclusive
[Files]
Source: "srcpath"; DestDir: "dirpath"; Components: connect\compA
Source: "srcpath"; DestDir: "dirpath"; Components: connect\compB
It looks like this
So if "Bob" wants to choose componenB he can not use ComponentA without automatic deselect componentB
So now if "Bob" already installed ComponentA and wants to install ComponentB and u dont want that both components are installed u need to use installdelete
example:
[InstallDelete]
Type: filesandordirs; Name: "dirpath\compA"; Components: connect\compB;
Type: filesandordirs; Name: "dirpath\compB"; Components: connect\compA;
I hope this will help
My idea is to offer the user the choice of installing the application either in {localappdata} or {commonappdata}, and that part works fine. However, I'm using custom Inno Setup skinning support, which requires a couple functions to get loaded during installation/uninstallation.
I have a DefaultAppDataFolder(): String function which returns the folder that the user chose (either common or local appdata one), and it works fine during installation. However, when I try to uninstall the app, it throws following error right upon execution:
Script error: Could not call proc
You can see that in the DefaultAppDataFolder() function I'm getting the uninstall directory in a bit shady way, extracting the file directory twice from the {UninstallExe} constant, maybe there is a better way to retrieve this?
Here is my script:
#define ApplicationName "MyApp"
#define ApplicationExe "app.exe"
#define ApplicationInstanceMutex "APPMUTEX"
#define InstallerFilename "install_app"
#define SkinName "Carbon.vsf"
[Setup]
AppName={#ApplicationName}
AppVerName={#ApplicationName}
DefaultDirName={code:DefaultAppDataFolder}
DefaultGroupName={#ApplicationName}
UninstallFilesDir={code:DefaultAppDataFolder}\uninstall
UninstallDisplayName={#ApplicationName}
Compression=lzma2
SolidCompression=yes
OutputDir=.\
DisableDirPage=yes
OutputBaseFilename={#InstallerFilename}
UninstallDisplayIcon={code:DefaultAppDataFolder}\{#ApplicationExe}
DisableProgramGroupPage=yes
AppMutex={#ApplicationInstanceMutex}
WizardImageFile=installer_images\installer-1.bmp
WizardSmallImageFile=installer_images\installer-2.bmp
[Files]
Source: "skins\VclStylesInno.dll"; DestDir: "{code:DefaultAppDataFolder}"; Flags: uninsneveruninstall ignoreversion
Source: "skins\{#SkinName}"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "root_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "client_files\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
Source: "ssl_libs\*.*"; DestDir: "{code:DefaultAppDataFolder}"; Flags: ignoreversion
[Icons]
Name: "{group}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; WorkingDir: "{code:DefaultAppDataFolder}"
Name: "{group}\Uninstall"; Filename: "{uninstallexe}"
Name: "{commondesktop}\{#ApplicationName}"; Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Tasks: desktopicon
[Run]
Filename: "{code:DefaultAppDataFolder}\{#ApplicationExe}"; Description: "Launch {#ApplicationName}"; Flags: postinstall nowait runascurrentuser
[Tasks]
Name: commondir; Description: "&All users"; GroupDescription: "Install For:"; Flags: exclusive
Name: localdir; Description: "&Current user"; GroupDescription: "Install For:"; Flags: exclusive unchecked
Name: desktopicon; Description: "Create a &desktop icon"
[Code]
procedure LoadVCLStyleS(VClStyleFile: String); external 'LoadVCLStyleW#files:VclStylesInno.dll stdcall setuponly';
procedure UnLoadVCLStylesS; external 'UnLoadVCLStyles#files:VclStylesInno.dll stdcall setuponly';
procedure LoadVCLStyleU(VClStyleFile: String); external 'LoadVCLStyleW#{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU; external 'UnLoadVCLStyles#{code:DefaultAppDataFolder}\VclStylesInno.dll stdcall uninstallonly';
var
ApplicationUninstalled: Boolean;
WizardInitialized: Boolean;
function InitializeSetup(): Boolean;
var
C1: Integer;
begin
ExtractTemporaryFile('{#SkinName}');
LoadVCLStyleS(ExpandConstant('{tmp}\{#SkinName}'));
result := TRUE;
end;
procedure InitializeWizard();
begin
WizardInitialized := TRUE;
end;
procedure DeinitializeSetup();
begin
UnLoadVCLStylesS;
end;
function InitializeUninstall(): Boolean;
begin
LoadVCLStyleU(ExpandConstant('{code:DefaultAppDataFolder}\{#SkinName}'));
result := TRUE;
end;
procedure InitializeUninstallProgressForm();
begin
ApplicationUninstalled := TRUE;
end;
procedure DeinitializeUninstall();
begin
UnLoadVCLStylesU;
UnloadDLL(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));
if ApplicationUninstalled then
begin
DeleteFile(ExpandConstant('{code:DefaultAppDataFolder}\VclStylesInno.dll'));
RemoveDir(ExpandConstant('{code:DefaultAppDataFolder}'));
end;
end;
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var
mres: integer;
begin
case CurUninstallStep of
usPostUninstall: begin
mres := MsgBox('Do you want to delete user data?', mbConfirmation, MB_YESNO or MB_DEFBUTTON2)
if mres = IDYES then
begin
DelTree(ExpandConstant('{localappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
DelTree(ExpandConstant('{userappdata}\{#ApplicationName}'), TRUE, TRUE, TRUE);
end;
end;
end;
end;
function DefaultAppDataFolder(Param: String): String;
begin
if IsUninstaller then
result := ExtractFileDir(ExtractFileDir(ExpandConstant('{uninstallexe}')))
else
if (WizardInitialized) and
(IsTaskSelected('localdir')) then
result := ExpandConstant('{localappdata}') + '\Programs\{#ApplicationName}'
else
result := ExpandConstant('{commonappdata}') + '\Programs\{#ApplicationName}';
end;
The error you got is not related to the uninstaller; you can narrow the problem down to this:
[Setup]
AppName=My Program
AppVersion=1.5
DefaultDirName=My Program
[Code]
procedure DoSomething;
external 'DoSomething#{code:GetLibPath}\MyLib.dll stdcall setuponly';
function GetLibPath(Value: string): string;
begin
Result := 'C:\ValidPathToLib';
end;
From the above script it seems that you cannot use scripted constants for imported DLL file names. And even delayed loading didn't workaround this limit. But for your case you can use just {app} path since your library is actually there (if I get your intention right):
...
procedure LoadVCLStyleU(VClStyleFile: string);
external 'LoadVCLStyleW#{app}\VclStylesInno.dll stdcall uninstallonly';
procedure UnLoadVCLStylesU;
external 'UnLoadVCLStyles#{app}\VclStylesInno.dll stdcall uninstallonly';
...
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;