Inno Setup script: Identifier expected error - inno-setup

Please help me with the following code:
[Code]
var
AppVersionNumber: Integer;
DBVersionNumber: Integer;
function GetAppVersion:Integer;
var
AppVersion: AnsiString;
begin
ExtractTemporaryFile('info.dat');
LoadStringFromFile(ExpandConstant('{tmp}\info.dat'), AppVersion);
AppVersionNumber := StrToInt(Copy(AppVersion, 1, 6));
DBVersionNumber := StrToInt(Copy(AppVersion, 7, 12));
GetAppVersion := AppVersionNumber; <== here is error
end;
I don't understand what's wrong here. The Inno setup says there is "Identifier expected" error. If I try to replace on this line GetAppVersion to Result (why? I don't know but I saw it in examples) it says that "Invalid prototype for GetAppVersion".
What's wrong with this code? Please help

Result := is needed to specify the result/return value of a function (you don't assign it to the function name like VB)
The "Invalid Prototype" error is most likely because you're using it in a {code:...} constant that requires the called function to have a single string parameter at all times.
Try using this taken from the help file:
function GetAppVersion(Param: String): String;

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

Inno Setup: Function to select a component

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".

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;

Error in the AssemblyInfo file

I get the error "Error 1(E4) "end." or implementation section members (types or methods) expected."
Nowhere on the internet I can find information about this error.
I get this error because of this line of the AssemblyInfo.pas file:
Implementation
SomeMethod();
end.
I work in Delphi Prism.
That's not valid inside implementation.
The Pascal (which Delphi Prism is based loosely on) unit consists of a couple of sections. The interface section provides the same functionality as the C/C++ header file; it exposes the public content to users of the code unit.
The implementation is like the C/C++ source file that the header exposes. It's where you actually implement the content the interface unit made available. Therefore, it should contain the actual code for the methods and functions.
A quick example (Delphi code, but is pretty similar):
unit Test.NyClass;
interface
// Defines types and so forth that, if exposed via the proper declaration, can be seen outside
// this unit simmply by adding this unit to the uses clause of the calling code.
uses
SysUtils;
type
TMyClass=class(TObject)
FMyNumber: Integer; // protected members (no specifier, so defaults to protected)
FMyString: String;
private
function GetMyNumber: Integer; // Getters
function GetMyString: string;
procedure SetMyNumber(const Value: Integer); // Setters
procedure SetMyString(const Value: string);
published
property MyNumber: Integer read GetMyNumber write SetMyNumber; // properties exposed to class users
property MyString: string read GetMyString write SetMyString;
end;
implementation
// Actually provides the implementation for the getters/setters, any additional methods,
// types not needed outside this implementation section, etc.
// Optional uses clause. Add units here you only need access to in the implementation code;
// this prevents circular references ("Unit A uses Unit B which uses Unit A").
uses
SomeOtherUnit;
// Implementation of the getters and setters declared for the properties above. Outside code
// can't call these directly (they were declared as private), but they're called automatically
// when the corresponding property is referenced.
function TMyClass.GetMyNumber: Integer;
begin
Result := FMyNumber;
end;
function TMyClass.GetMyString: string;
begin
Result := FMyString;
end;
procedure TMyClass.SetMyNumber(const Value: Integer);
begin
if FMyNumber <> Value then
FMyNumber := Value;
end;
procedure TMyClass.SetMyString(const Value: string);
begin
if FMyString <> Value then
FMyString := Value;
end;
// Optional initialization section. This is what your code is probably intending to use (if Prism
// supports it - don't have it on this machine to check).
initialization
// Any necessary loading initialization, etc. Called when the unit is being loaded into memory,
// so you have to be careful what you're doing here.
// Optional finalization section. This is where you do cleanup of anything allocated in the
// initialization section.
finalization
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