Evaluate a collection of data from preprocessor on run time in Inno Setup Pascal Script - inno-setup

I am trying to get Inno Setup define value in Code section but not with {#VersionTool1}. I need to pass defined name dynamically, because there are a lot of them (I want to avoid large switch case). I tried SetupSetting but it's not in Setup section (it's before it). Is there any way to do this?
#define VersionTool1 2019.01.1111
#define VersionTool2 2020.02.2111
...
[Code]
procedure SetSelectedTool(ToolName: String);
var
CurrentTool: string;
begin
...
CurrentTool := 'Version' + ToolName;
CurrentToolVersion := {#CurrentTool};
...
end;
Value of local variable CurrentTool wil for example be 'VersionTool1' and I want to get value of VersionTool1 preprocessor variable which is 2020.02.2111.

It's not possible, see Evaluate preprocessor macro on run time in Inno Setup Pascal Script.
But there are other solutions.
For example:
[Code]
var
ToolNames: TStringList;
ToolVersions: TStringList;
function InitializeSetup(): Boolean;
begin
ToolNames := TStringList.Create;
ToolVersions := TStringList.Create;
#define AddToolVersion(Name, Version) \
"ToolNames.Add('" + Name + "'); ToolVersions.Add('" + Version +"');"
#emit AddToolVersion('Tool1', '2019.01.1111')
#emit AddToolVersion('Tool2', '2020.02.2111')
{ ... }
Result := True;
end;
(of course, the above makes sense only if you actually do not hardcode the version numbers, but use a code that only a preprocessor can do – something like GetStringFileInfo, what I've understood from your comments that you plan to)
And then you can have a function like:
function GetToolVersion(ToolName: string): string;
var
I: Integer;
begin
I := ToolNames.IndexOf(ToolName);
if I >= 0 then Result := ToolVersions[I];
end;
Another similar questions:
Array Variables and dynamic access in [Code] section
Scripting capabilities in the Registry section

Related

How do I copy a source file from a directory specified by the user? [duplicate]

So given this function, I get the error "Identifier Expected" on the GetRoot := ROOTPage.Values[0]; line. I expect it is telling me that the ROOTPage is not defined?
const
DefaultRoot = 'C:\IAmGRoot';
Var
ROOTPage : TInputQueryWizardPage;
procedure SetupRoot;
begin
ROOTPage := CreateInputQueryPage(wpUserInfo,
ExpandConstant('{cm:RootTitle}'),
ExpandConstant('{cm:RootInstructions}'),
ExpandConstant('{cm:RootDescription}') + ' "' + DefaultRoot + '"'
);
ROOTPage.Add(ExpandConstant('{cm:SSRoot}') + ':', False);
ROOTPage.Values[0] := ExpandConstant('{DefaultRoot}');
// add SSROOT to path
end;
function GetRoot : string;
begin
GetRoot := ROOTPage.Values[0];
end;
How should I interpret this error. What is an identifier in Pascal?
This page tells me that identifiers are variable names. Perhaps I need to expand the ROOTPage.Values[0] in some way since I am referencing an array from an Inno Setup object?
Or maybe I need to return the value differently. I saw one page on Pascal that said that you needed to avoid assigning to the function value on parameter less functions to avoid a recursive loop. Does this mean I should pass in a dummy value? or is there a different syntax? That page did not explain.
I secretly think my real issue is that I am not defining my function correctly... but well. That much compiles at least. This question could become: How do you handle a parameter-less function in Pascal?
I do not think Inno Setup is part of the issue, but I am working with Inno Setup in case that is important.
Update:
It doesn't seem to be the array because this gets the same error:
const
DefaultRoot = 'C:\IAmGRoot';
function GetRoot : string;
begin
GetRoot := DefaultRoot;
end;
Update:
This link has said that the function name can be replaced/ should be replaced with the key word Result such as the following code. I actually knew this, but the Inno Setup compiler does not recognize this as valid syntax. It then tells me my function is an invalid prototype.
function GetRoot : string;
begin
Result := DefaultRoot;
end;
Update:
If I do this I get "Invalid Prototype for GetRoot"
function GetRoot : boolean;
begin
Result := False;
end;
Update for #Martin Prikryl:
Well I use it a few places but the typical use would be like this:
[Files]
Source: "C:\ValidPath\Release\*"; DestDir: "{app}\bin"; Components: DefinedComponent
Source: "C:\ValidPath\Deployment\*"; DestDir: "{code:GetRoot}\"; Flags: ignoreversion recursesubdirs; Components: DefinedComponent
Identifier expected
Your code would be correct in a Pascal, but it does not compile in Pascal Script.
In Pascal, when you want to assign a return value of a function, you either assign the value to a "variable" with a name of the function or to Result variable.
So this is correct:
function GetRoot: string;
begin
GetRoot := ROOTPage.Values[0];
end;
And this too (both are equivalent):
function GetRoot: string;
begin
Result := ROOTPage.Values[0];
end;
In the Pascal Script, only the Result works. When you use the name of the function, you get the "Identifier expected."
Invalid prototype
You get this when the function is called from outside of the Code section and a specific parameter list/return value is required. But you didn't tell us, what you use the GetRoot function for.
There are two places, where you can use a custom function in Inno Setup:
Check parameter: For this the function must return a Boolean and take either no parameter or one parameter (the parameter type is determined by a value you provide in the Check parameter).
function MyProgCheck(): Boolean;
function MyDirCheck(DirName: String): Boolean;
Scripted Constants: The function must return a string and take one string parameter, even if no parameter is provided in the scripted constant. I assume this is your use case. If you do not need any parameter, just declare it, but do not use it:
function GetRoot(Param: String): string;
begin
Result := ROOTPage.Values[0];
end;

Inno Setup define a hexadecimal color constant

I am trying to use the [ISPP] section to define a hexadecimal color which will later be used in the [Code] section as a spot color, the value of which may change in the future, but I am getting a type mismatch error when running. Here are the relevant sections from the code:
[ISPP]
#define ColorPetrol "$C8C264"
[Code]
procedure InitializeWizard();
var
PortLabel: TNewStaticText;
begin
PortLabel := TNewStaticText.Create(WizardForm);
PortLabel.Caption := 'Port';
PortLabel.Top := ScaleY(78);
PortLabel.Parent := Page.Surface;
PortLabel.Font.Color := ExpandConstant('{#ColorPetrol}');
end;
I am assuming the error is caused by the define constant being a string and the PortLabel.Font.Color requiring a hex value. How can the constant be defined in the [ISPP] section and used in this way correctly?
Just use PortLabel.Font.Color := {#ColorPetrol};. ExpandConstant() is for expanding built-in Inno Setup constants, not for ISPP defines. The latter really are just about textual replacements.
As a side note, I'm not aware of an [ISPP] section. IMO you should just move the define to the [Code] section.

Conditional DisableProgramGroupPage in Inno Setup

I'm trying to create a single installer for both normal and portable installs. For the portable install I am disabling all icons and uninstaller creation.
The only problem I am stuck at is how to disable program group page when running the portable install. Am I misunderstanding something here?
[Setup]
;This works as expected
Uninstallable=not IsPortable()
;This does NOT work, can't compile (DisableProgramGroupPage=yes alone compiles fine)
DisableProgramGroupPage=yes IsPortable()
Compilation fails with error
Value of [Setup] section directive ... is invalid.
This is the IsPortable() function:
function IsPortable(): Boolean;
begin
if(StandardRadioButton.Checked = True) then
Result := False
else
Result := True;
end;
(Elaborating on #TLama's comment)
The DisableProgramGroupPage does not support "boolean expression":
[Setup]: DisableProgramGroupPage
Valid values: auto, yes, or no
Contrary to Uninstallable:
[Setup]: Uninstallable
Valid values: yes or no, or a boolean expression
You can use ShouldSkipPage event function instead:
function ShouldSkipPage(PageID: Integer): Boolean;
begin
Result := False;
if PageID = wpSelectProgramGroup then
begin
Result := IsPortable;
end;
end;

Is it possible to build a Inno Setup script line from variables

Is it possible to build a script line using a variable and some conditions (have executable that requires different switches depending on what is checked on a custom page. Possibly something like this:
var
linecommand : string;
function FileParams();
begin
if check1 then linecommand := linecommand+' conditionone' end;
if check2 then linecommand := linecommand+' conditiontwo' end;
if check3 then linecommand := linecommand+' conditiontwo' end;
end;
function check123()
begin
if check1 or check2 or check3 then
begin
linecommand='Executable file name.exe '+linecommand;
Shellexec(linecommand);
end;
end;
You can use a {code:...} constant to insert a value calculated in a [Code] function into a specific value within a standard entry that accepts both strings and constants (such as the Parameters value of a [Run] entry).
Or you can write multiple entries and use a Check function to determine which (if any) of them actually get executed.

Inno Setup comma error

I have GetVersion function in [Code] that returns a string like this "1004", "1003", etc.
I created this function to check the registry value for lowest version numbers and uninstall them.
Here is a snippet of the code it is giving error point to StrtoInt conversion line stating
Comma (,) expected
Here is the snippet:
function DoesOldVersionsExist(): Boolean;
var
AppVersion: integer;
mstr: string;
VersionInstalled: cardinal;
begin
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
...
after that line I'm simple comparing the values and return true or false. Much Appreciated.
This is what error message says:
Line 55
Column 40.
Comma (,) expected
Thanks Deanna but unfortunately that is the error message pointing to this :
AppVersion := StrToInt(GetVersion({#MyAppVersion}), 0);
^
Here is the GetVersion function:
function GetVersion(AppVersion: String): String;
var
Version: String;
CharIndex: integer;
c: char;
begin
for CharIndex := 1 to Length(AppVersion) do begin
c := AppVersion[CharIndex];
if (c <> '.') then
Version := Version + c;
end;
Result := Version;
end;
I think that you can't just have Inno Setup constants in code like this, you have to use ExpandConstant():
AppVersion := StrToInt(GetVersion(ExpandConstant('{#MyAppVersion}')), 0);
You have not given us enough information to give a definite answer, but I think that the situation is as follows.
You have defined some constant called MyAppVersion which you let the ISPP (the Inno Setup pre-processor) substitute. Now, you have not told us what type this variable is, and you have not told us what the signature of GetVersion is (in particular, what type of argument does it expect?). However, if these types are strings, you need to write
StrToInt(GetVersion('{#MyAppVersion}'), 0);
in order to obtain, say,
StrToInt(GetVersion('Some string, this is!'), 0);
instead of
StrToInt(GetVersion(Some string, this is!), 0);
which is malformed (indeed, to such an extent that it hurts my eyes to look at it).

Resources