InstallScript Traps and Pitfalls
- Logic Operators (&&, ||) have no short circuit effects.
- Parentheses in if statement are optional
- Equality comparison is written as a single equal sign (=)
- VerCompare function only applies to numeric version in w.x.y.z format
- LaunchAppAndWait does not wait by default
- LaunchApp requires complete path of the application
- Commas
- SYSINFO on previous versions of InstallShield
- Data Type keywords are case-sensitive
- ISERR_SUCCESS and ISERR_GEN_FAILURE
- String Size and Autosize
- Indirection Operator (*)
- Embed \0 in string
InstallScript is the language to create installations for InstallShield. And …
InstallScript is similar to the C language.
as stated in InstallScript Language Reference. But they resembles only in their written form, not in their semantics or syntax. So be careful!!
Logic Operators (&&, ||) have no short circuit effects.
Doc: Logical Operators (&&, ||, !)
Unlike C, InstallShield performs complete Boolean evaluations of logical expressions.
So in order to achieve short-circuit effect, rewrite if statements with compound expressions to nested if statements.
For example,
if ( Foo() && Bar() ) then
MessageBox( "Complete Boolean Evaluation", INFORMATION );
endif;
if ( Foo() ) then
if ( Bar() ) then
MessageBox( "Short-circuit evaluation", INFORMATION );
endif;
endif;
And,
if ( Foo() || Bar() ) then
MessageBox( "Complete Boolean Evaluation", INFORMATION );
endif;
if ( Foo() ) then
MessageBox( "Short-circuit evaluation", INFORMATION );
elseif ( Bar() ) then
MessageBox( "Short-circuit evaluation", INFORMATION );
endif;
Parentheses in if statement are optional
=
)
Equality comparison is written as a single equal sign (Doc: Relational Operators (<, >, =, <=, >=, !=)
Equality comparison is written as =
, though ==
also works (undocumented).
Unlike C, which uses == to test for equality, InstallScript's assignment operator and relational operator use the same symbol ( = ).
VerCompare function only applies to numeric version in w.x.y.z format
Doc: VerCompare
Only version number in format w.x.y.z is valid, comparing versions in other formats result in ISERR_GEN_FAILURE (-1).
Characters other than number characters are actually allowed, but they are ignored when doing comparison. e.g.
-
VerCompare( "1.2.3.4rc", "1.2.3.4", VERSION )
returns EQUALS (2) -
VerCompare( "1.2.3.04", "1.2.3.4", VERSION )
returns EQUALS (2) -
VerCompare( "v1.2.3.4", "v2.2.3.4", VERSION )
returns EQUALS (2) -
VerCompare( "1.2.3.rc", "1.2.3.4", VERSION )
returns LESS_THAN (1) -
VerCompare( "v1.2.3.4", "1.2.3.4", VERSION )
returns LESS_THAN (1) -
VerCompare( "v2.1.3.4", "v1.2.3.4", VERSION )
returns LESS_THAN (1) -
VerCompare( "v1.3.3.4", "v2.2.3.4", VERSION )
returns GREATER_THAN (0)
LaunchAppAndWait does not wait by default
Doc: LaunchAppAndWait
To actually launch an app and wait for it, you need to pass the LAAW_OPTION_WAIT
option:
LaunchAppAndWait( szProgram, szCmdLine, LAAW_OPTION_WAIT );
If the launched program spawns a child process and exits itself, LAAW_OPTION_WAIT_INCL_CHILD
option is also needed.
LAAW_OPTION_NOWAIT is the default
Actually, the value of the predefined constant LAAW_OPTION_NOWAIT
is 0
, thus specifying it is totally optional.
LaunchApp requires complete path of the application
LaunchApplication/LaunchAppAndWait/LaunchApp requires complete path of the application.
Otherwise, it failes with ISERR_GEN_FAILURE
(-1) as the return value.
Commas
(Not documented)
Suprisingly, ,
(fullwidth comma, \uff0c
) can be used in place of ,
(comma, '\u002c').
SYSINFO on previous versions of InstallShield
SYSINFO.nOSMajor
, SYSINFO.nOSMinor
, SYSINFO.nWinMajor
, SYSINFO.nWinMinor
on InstallShield 2013 and InstallShield 2013 SP1 report version number up to 6.2 only, i.e., Windows Server 2012 R2 (6.3), Windows 10 (10.0), etc., will be reported as 6.2.
Data Type keywords are case-sensitive
Though most Data Type keywords can be entered in either lowercase or uppercase:
- binary/BINARY
- char/CHAR
- int/INT
- long/LONG
- number/NUMBER
- object/OBJECT
- pointer/POINTER
- short/SHORT
- string/STRING
- variant/VARIANT
- void/VOID
- wpointer/WPOINTER
- wstring/WSTRING
while others are uppercase only:
- BOOL
- HWND
- LIST
- LPSTR
- LPWSTR
So the best practise is to always use the uppercase form.
ISERR_SUCCESS and ISERR_GEN_FAILURE
ISERR_SUCCESS (0) and ISERR_GEN_FAILURE (-1) are predefined constants returned by built-in functions.
Values greater than zero are also returned by built-in functions, whose meaning are dependent on called functions, but always mean it's executed successfully.
Values less than zero will also returned by built-in functions when the error is specific and has a separate error code.
So to test whether a built-in function execute successfully, best practice is to compare it with ISERR_SUCCESS (0):
if ( nResult >= ISERR_SUCCESS ) then
// Success
// ...
endif;
if ( nResult < ISERR_SUCCESS ) then
// Error
// ...
endif;
Do NOT compare with ISERR_SUCCESS itself only:
// The following is prone to bug
if (nResult) then
// Success (>0) or Error (<0)
// ...
endif;
String Size and Autosize
Doc: String Size and Autosize, BYREF Operator
String without size specified is auto sized.
Note that an autosized string variable that is passed by reference to a function will not be autosized within the called function. If the function attempts to assign a value whose length is greater than the current size of that parameter, run-time error 401 occurs. To avoid this error, declare strings with a specific size when they are to be passed by reference to a function.
Indirection Operator (*)
The indirection operator can be used with number pointers only.
Embed \0 in string
Embed \0 in string literal is possible, but most built-in functions simply ignores all values after first \0, including +
operator for string concatenation.
svTest = "a\0b\0c"; // => "a\0b\0c\0"
svTest = "A\0B" + "C\0D"; // => "AC\0"
To concat strings with embeded \0, use CopyBytes()
. And keep track of the length of string yourself, as functions like StrLength()
or StrLengthChars()
doesn't work either.
Strings with embeded null byte are useful in LAAW_PARAMETERS.lpEnvironment
for example.