Inno Setup: Function to select a component - inno-setup

I have a small problem. I need that a page is displayed when you select one or two components. But the other is not work only with a single component seems to have an effect. I leave the code that I'm working.
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program
[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
[Code]
var
Page1: TWizardPage;
Procedure InitializeWizard();
begin
Page1:= CreateCustomPage(wpSelectComponents, 'Custom wizard page 1', 'TButton');
end;
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Case PageID of
Page1.ID: Result:= not IsComponentSelected('help');
Page1.ID: Result:= not IsComponentSelected('readme\de'); // It does not work
end;
end;
A greeting and thanks in advance.

If you need to write more complex conditions, use logical operators for that. In this case you wanted to use the and operator:
Result := not IsComponentSelected('help') and not IsComponentSelected('readme\de');
Which can be read as:
Skip page if "help" component is not selected and "readme\de"
component is not selected as well. In human language it could be, skip
page if neither "help" nor "readme\de" component is selected.
Your code so can be simplified to this:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
// skip the page if it's our custom page and neither "help" nor "readme\de"
// component is selected, do not skip otherwise
Result := (PageID = Page1.ID) and (not IsComponentSelected('help') and
not IsComponentSelected('readme\de'));
end;
One final note (and a possible cause of problems), beware of switching on the same identifier in case statements. Compiler should not allow you doing this but unfortunately does, e.g. this compiles:
var
I: Integer;
begin
I := 1;
case I of
1: MsgBox('Case switch 1.1', mbInformation, MB_OK);
1: MsgBox('Case switch 1.2', mbInformation, MB_OK);
end;
end;
But only the first switch value statement executes, so you'll never see the message "Case switch 1.2".

Related

"Acess violation" when using a scripted constant

I need to implement a scripted constant to retrieve a drive of user-selected path.
I tried the code bellow, but I'm getting:
Acess violation ate adress 0043D8E0.Read of address 01CDE694
[Code]
procedure InitializeWizard;
begin
Page := CreateInputDirPage(
wpSelectDir,'Select local', 'Where will be stored?', '', False, 'New Folder');
Page.Add('Local Dserver (APP)');
Page.Add('Local Images (Storage)');
Page.Values[0] := ('F:\TEST1');
Page.Values[1] := ('G:\TEST2');
end;
function ExtractFileDrive(const FileName: string): String;
begin
Result := ExtractFileDrive(Page.Values[0]);
end;
[Run]
Filename: {code:ExtractFileDrive|0}\postgresql-9.4.5-1-windows-x64.exe
Your ExtractFileDrive scripted constant shadows the ExtractFileDrive support function. So you recursively call your ExtractFileDrive function from itself ad infinitum, until the stack overflows.
Just rename your function to anything else.
And once doing that, rename its argument, as the FileName is confusing. And also remove the scripted constant parameter in its use, as you actually do not use it.
[Code]
function GetFileDrive(Param: string): String;
begin
Result := ExtractFileDrive(Page.Values[0]);
end;
[Run]
Filename: {code:GetFileDrive}\postgresql-9.4.5-1-windows-x64.exe

Default behavior and custom behavior for changing the type combobox in inno setup

In my setup tool I want a specific behavior on the Select Components wizard page. The installer contains several types, one of them is a custom. If the user selects one of the setup types, it is not possible to change the check boxes (similar to components flagged fixed). But if the user selects "custom", the checkboxes are supposed to be enabled.
Enable and disable the checkboxes can easily be done by changing the procedure WizardForm.TypesCombo.OnChange. When doing so unfortunately the default behavior with selecting the components according to the setup types does not work anymore.
The question is, how can I do both on the "change" event of the type combo box?
I tried to store the default implementation into a function pointer and call this in the customized change procedure (see commented lines in the code), but did not succeed. I am getting compiler errors.
Here is my inno setup script:
[Setup]
AppId={{8D76F99A-82A1-4995-A470-BA9B69F83F67}
AppName=MyAppName
AppVersion=1.0.1
Uninstallable=no
DefaultDirName=C:\MyPath\Versions
SetupLogging=yes
[Types]
Name: "full"; Description: "Complete installation (Base System & optional 3rd Party SW)";
Name: "base_only"; Description: "Basic installation without optional";
Name: "custom"; Description: "Custom installation"; Flags: iscustom
[Components]
Name: "Base"; Description: "Base with required 3rd Party SW"; Types: full base_only ;
Name: "Base\Redist"; Description: "Redistributables"; Types: full base_only ;
Name: "Base\NTP"; Description: "NTP"; Types: full base_only ;
Name: "Base\WinSCP"; Description: "WinSCP"; Types: full base_only ;
Name: "ThirdPartyOptional"; Description: "Optional 3rd Party SW"; Types: full ;
Name: "ThirdPartyOptional\7Zip"; Description: "7Zip"; Types: full ;
Name: "ThirdPartyOptional\WinMerge"; Description: "WinMerge"; Types: full ;
Name: "ThirdPartyOptional\Notepad"; Description: "Notepad++"; Types: full ;
Name: "ThirdPartyOptional\Putty"; Description: "Putty"; Types: full ;
[Code]
type
TMyOnChange = procedure(Sender: TObject);
procedure TypeChange (Sender: TObject);
var
i: Integer;
begin
for i := 0 to WizardForm.ComponentsList.Items.count - 1 do
begin
WizardForm.ComponentsList.ItemEnabled[i] := (WizardForm.TypesCombo.Text = 'Custom installation');
end;
//TMyOnChange(Sender); // this throws an compiler error: type mismatch
end;
procedure InitializeWizard;
begin
// try to get default implementation of types combo change
//TMyOnChange := WizardForm.TypesCombo.OnChange; // this throws an compiler error: internal error (20)
// add callback function for type changed
WizardForm.TypesCombo.OnChange := #TypeChange;
// initialize the wpSelectComponents page
TypeChange(nil);
end;

Pascal Scripting: Canceling setup before {app} variable is set

I have some declarations at the [Dirs]-section in my Inno Setup file. I use "Inno Setup Compiler" and a normal text editor (Notepad++) for developing.
When I cancel the setup before choosing the install directory, the {app} variable is empty for sure.
I get this error (which is totally logic):
How can I fix that no error occurs after pressing the "Cancel" button and committing that I want to cancel the setup?
Internal error: An attempt was made to expand the "app" constant
before it was initialized.
Can I globally set the {app} variable or give it a default value?
Here is a code snippet where I use the variable {app}:
[Dirs]
Name: {app}; Permissions: everyone-readexec
Name: {app}\bin; Permissions: everyone-readexec
[Run]
Filename: "{app}\run.exe; Flags: runhidden
[INI]
Filename: {app}\bin\myIni.ini; Section: Settings;
[InstallDelete]
Name: {app}\*; Type: filesandordirs; Tasks:
Thanks for help,
regards,
C.
Either you should skip the code, which attempts to expand the {app} constant before it's initialized, or as a workaround you can use the WizardDirValue, which actually returns value to the {app} when it's being expanded. Even reference mentions that (emphasized by me):
Returns the current contents of the edit control on the Select
Destination Location page of the wizard.
Unlike ExpandConstant('{app}'), this function will not fail if called after the wizard is shown but prior to the user selecting a
directory. Rather, it will return the default directory name.
In the most recent source code you can see how the {app} constant is expanded on this line.
Thanks for helping, the problem got solved!
Before the user reaches the 'Select Destination Location' the {app} variable is not set.
My DeInitialize-Procedure looked like this:
procedure DeinitializeSetup();
var
SettingsPath: String;
begin
SettingsPath := ExpandConstant('{app}')
DelTree(SettingsPath + '\bin', True, True, True);
end;
What I did is I created a Boolean variable at the beginning:
[Code]
var appIsSet: Boolean;
I set it to false at initializing:
function InitializeSetup(): Boolean;
begin
// interesting code
appIsSet := False;
end;
... and set it to 'true' after the user has reached 'wpSelectDir' in nextButtonClick (see code snippet below:)
begin
if CurPageID = wpSelectDir then
begin
appIsSet := True;
The last step is to check in the Deinitialize-Procedure if the boolean variable is set. If so, he can access on it, if not - do nothing:
procedure DeinitializeSetup();
var
SettingsPath: String;
begin
if appIsSet then begin
SettingsPath := ExpandConstant('{app}')
DelTree(SettingsPath + '\bin', True, True, True);
end;
end;

Add installation type, maintain the predefined ones

I'd like to add an own installation type into an Inno setup project, while keeping the original ones (Full, Compact and Custom). The problem is, when I create the [Types] section, these installation types are lost and I have to redefine them.
If this is not possible, okay then, let's redefine them. But I'd like to use the original language constants from the .isl files. I haven't found any option, how to use [Message]-like declarations as constants in [CustomMessage] way (e. g. {cm:LaunchProgram}) in the Types' Description parameter. Is there any option, how to do this?
Here is how you can do it, using [CustomMessages]
[CustomMessages]
FullInstall=Full installation
CompactInstall=Compact installation
CustomInstall=Custom installation
[Types]
Name: "full"; Description: "{cm:FullInstall}"
Name: "compact"; Description: "{cm:CompactInstall}"
Name: "custom"; Description: "{cm:CustomInstall}"; Flags: iscustom
Here is how you can do it using [Messages] values.
[Types]
Name: "full"; Description: "{code:FullInstall}"
Name: "compact"; Description: "{code:CompactInstall}"
Name: "custom"; Description: "{code:CustomInstall}"; Flags: iscustom
[Code]
function FullInstall(Param : String) : String;
begin
result := SetupMessage(msgFullInstallation);
end;
function CustomInstall(Param : String) : String;
begin
result := SetupMessage(msgCustomInstallation);
end;
function CompactInstall(Param : String) : String;
begin
result := SetupMessage(msgCompactInstallation);
end;

How to automatically determine the path of previous installation using Inno Setup

I'm trying to create a inno setup installer that patches a previous installation but i can't manage to force my installer determine the path where my previous installation is.
I tried using the DefaultDirName={reg:HKxx\SubkeyName,ValueName|DefaultValue} feature from inno but i'm not sure what to put in the DefaultValue's place.
How can i do that?
Edit:
i tried also this part:
[Setup]
DefaultDirName={code:GetPathInstalled}
[Code]
function GetPathInstalled (Param: String): String;
var
Country: String;
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\JoWooD\Painkiller Resurrection', 'Install', Country);
end;
But when i run the installer the path is empty.
Your code should look like:
[Code]
function GetPathInstalled (Param: String): String;
var
Country: String;
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\JoWooD\Painkiller Resurrection', 'Install', Country);
Result:= Country;
end;
The return value from the RegQueryStringValue wasn't being returned as the result of the GetPathInstalled function.

Resources